gobyexample通关笔记

admin 2024年4月10日15:36:54评论13 views字数 24708阅读82分21秒阅读模式

项目地址:Go by Example

Hello World

package main  

import "fmt"  

func main() {  
  fmt.Println("Hello World")  
}

Values

package main  

import "fmt"  

func main() {  
  fmt.Println("go" + "lang")  
  fmt.Println("1+1=", 1+1)  
  fmt.Println("7.0/3.0", 7.0/3.0)  
  fmt.Println(true && false)  
}

fmt.Println() 函数是一个可变参数函数,可以接受任意数量的参数,并在输出时将它们格式化为字符串。在执行 fmt.Println("1+1=", 1+1) 时,Go 会将第一个参数 "1+1=" 和第二个参数 1+1格式化为字符串,并将它们连在一起输出。由于1+1 是一个表达式,它会在编译时求值并将结果转换为字符串。

Variables

package main  

import "fmt"  

func main() {  
  var a = "golang"  
  var b, c = 12, 34  
  var d = true  
  e := "ry4n"  
  fmt.Println(a, b, c, d, e)  
}

Constants

package main  

import (  
  "fmt"  
  "math")  

const s string = "conststring"  

func main() {  
  fmt.Println(s)  
  const n = 500  
  fmt.Println(n)  
  fmt.Println(int64(n))  
  fmt.Println(math.Sin(n))  
}

数值型的常量在被赋予类型之前没有类型,例如显示转换。

For

package main  

import "fmt"  

func main() {  
  i := 1  
  for i < 5 {  
      fmt.Println(i)  
      i++  
  }  
  for j := 1; j < 3; j++ {  
      fmt.Println(j)  
  }  
  for k := 0; k < 5; k++ {  
      if k%2 == 0 {  
        continue  
      }  
      fmt.Println(k)  
  }  
}

If/Else

package main  

import (  
  "fmt"  
)  

func main() {  
  if 7%2 == 0 {  
      fmt.Println("even")  
  }  
  if 8%2 == 0 {  
      fmt.Println("odd")  
  }  
  if 7%2 == 0 && 8%2 == 0 {  
      fmt.Println(false)  
  }  
  if 7%2 == 0 || 8%2 == 0 {  
      fmt.Println(true)  
  }  
}

Switch

package main  

import "fmt"  

func main() {  
  var input string  
  fmt.Scanln(&input)  
  switch input {  
  case "1":  
      {  
        fmt.Println("input 1")  
      }  
  case "2":  
      {  
        fmt.Println("input 2")  
      }  
  case "3":  
      {  
        fmt.Println("input 3")  
      }  
  default:  
      fmt.Println("input others")  
  }  
}

Arrays

package main  

import "fmt"  

func main() {  
  var a [5]int  
  for i := range a {  
      fmt.Println(a[i])  
  }  
  a[1] = 3  
  fmt.Println(a[1])  
  fmt.Println(len(a))  

}

Slice

package main  

import (  
  "fmt"  
  "reflect")  

func main() {  
  var s []string  
  fmt.Println(reflect.TypeOf(s))  
  fmt.Println(len(s), cap(s))  

  s1 := make([]string, 5)  
  fmt.Println(reflect.TypeOf(s1))  
  fmt.Println(len(s1), cap(s1))  

  s1[0] = "a"  
  s1 = append(s1, "b")  
  fmt.Println(s1)  
  fmt.Println(len(s1), cap(s1))  

}

Map

package main  

import "fmt"  

func main() {  
  m := make(map[int]string)  
  m[1] = "first"  
  m[2] = "second"  
  fmt.Println(m)  
  delete(m, 1)  
  fmt.Println(m)  
  m = make(map[int]string)  
  fmt.Println(m)  
}

可以通过 make 创建一个新的 map,来删除原来 map 中的数据。

Range

package main  

import "fmt"  

func main() {  
  num := []int{2, 3, 4}  
  sum := 0  
  for _, i := range num {  
      sum += i  
  }  
  fmt.Println(sum)  
  m := make(map[string]string)  
  m["a"] = "apple"  
  m["b"] = "golang"  
  for k, v := range m {  
      fmt.Println(k, v)  
  }  
  for j := range m {  
      fmt.Println(j)  
  }  

}

Functions

package main  

import "fmt"  

func plus(a, b int) int {  
  return a + b  

}  

func main() {  
  res := plus(2, 3)  
  fmt.Println(res)  
}

Multiple Return Values

package main  

import "fmt"  

func test() (int, int) {  
  return 1, 2  
}  
func main() {  
  a, b := test()  
  fmt.Println(a, b)  
}

Variadic Functions

package main  

import (  
  "fmt"  
  "reflect")  

func sum(nums ...int) {  
  fmt.Println(nums, " ")  
  fmt.Println(reflect.TypeOf(nums))  
  total := 0  
  for _, num := range nums {  
      total += num  
  }  
  fmt.Println(total)  

}  

func main() {  
  sum(1, 2)  
  sum(1, 2, 3)  
  nums := []int{1, 2, 3, 4, 5}  
  sum(nums...)  
}

Closures

package main  

import "fmt"  

func intSeq() func() int {  
  i := 0  
  return func() int {  
      i++  
      return i  
  }  
}  

func main() {  

  nextInt := intSeq()  

  fmt.Println(nextInt())  
  fmt.Println(nextInt())  
  fmt.Println(nextInt())  

  newInts := intSeq()  
  fmt.Println(newInts())  
}

Recursion

package main  

import "fmt"  

func fact(n int) int {  
  if n == 0 {  
      return 1  
  }  
  return n * fact(n-1)  
}  

func main() {  
  fmt.Println(fact(5))  
}

Pointers

package main  

import "fmt"  

func zeroval(ival int) {  
  ival = 0  
}  

func zeroptr(iptr *int) {  
  *iptr = 0  
}  

func main() {  
  i := 1  
  fmt.Println("initial:", i)  

  zeroval(i)  
  fmt.Println("zeroval:", i)  

  zeroptr(&i)  
  fmt.Println("zeroptr:", i)  

  fmt.Println("pointer:", &i)  
}

Structs

package main  

import "fmt"  

type company struct {  
  name string  
  id   int  
}  

func newCompany(name string) *company {  
  item := company{name: name}  
  return &item  
}  

func main() {  

  fmt.Println(company{"AAA", 20})  
  fmt.Println(newCompany("BBB"))  

  fmt.Println(&company{name: "Ann", id: 40})  
  fmt.Println(company{name: "Ann", id: 40})  

}

Methods

package main  

import "fmt"  

type rect struct {  
  width int  
  height int  
}  

func (r *rect) area() int {  
  return r.width * r.height  
}  

func (r *rect) c() int {  
  return 2*r.width + 2*r.height  
}  

func main() {  
  re := rect{5, 3}  
  fmt.Println(re.area())  
  fmt.Println(re.c())  
}

golang 也支持在 struct 上定义方法。

Struct Embedding

package main  

import "fmt"  

type base struct {  
  num int  
}  

type container struct {  
  base  
  str string  
}  

func main() {  
  c := container{base{  
      num: 1,  
  }, "test"}  
  fmt.Println(c.base, c.str, c.num, c.base.num)  
}

Errors

package main  

import (  
  "errors"  
  "fmt")  

func f(arg int) (int, error) {  
  if arg == 42 {  

      return -1, errors.New("can't work with 42")  
  }  
  return arg + 3, nil  

}  

var ErrOutOfTea = fmt.Errorf("no more tea available")  
var ErrPower = fmt.Errorf("can't boil water")  

func makeTea(arg int) error {  
  if arg == 2 {  
      return ErrOutOfTea  
  } else if arg == 4 {  
      return fmt.Errorf("making tea: %w", ErrPower)  
  }  

  return nil  
}  
func main() {  
  err := makeTea(2)  
  fmt.Println(err)  
  _, err = f(42)  
  fmt.Println(err)  
}

Goroutines

package main  

import (  
  "fmt"  
  "time")  

func a(from string) {  
  for i := 0; i < 3; i++ {  
      fmt.Println(from, " : ", i)  
  }  
}  

func main() {  
  a("direct")  
  go a("goroutine")  

  go func(msg string) {  
      fmt.Println(msg)  
  }("going")  
  time.Sleep(time.Second)  
  fmt.Println("done")  
}

Channels

package main  

import "fmt"  

func main() {  
  messages := make(chan string)  
  go func() {  
      messages <- "ping"  
  }()  
  msg := <-messages  
  fmt.Println(msg)  
}

Channel Buffering

package main  

import "fmt"  

func main() {  
  messages := make(chan string, 2)  
  messages <- "buffered"  
  messages <- "channel"  

  fmt.Println(<-messages)  
  fmt.Println(<-messages)  
}

channel 默认是无缓冲的,因此需要有另一个 channel 接收。但是如果设置了有缓存的,则不需要。

Channel Synchronization

package main  

import (  
  "fmt"  
  "time")  

func worker(done chan bool) {  
  fmt.Println("working")  
  time.Sleep(time.Second)  
  fmt.Println("done")  
  done <- true  
}  

func main() {  
  done := make(chan bool, 1)  
  go worker(done)  

  <-done  
}

代码中的 <-done 表示主程序从通道 done中接收数据。在该程序中,当 worker goroutine 完成其工作后,它会将一个布尔值发送到 done 通道,而主程序则等待从 done 通道接收数据。如果删除了<-done,主程序就不会等待worker goroutine完成其工作。虽然worker goroutine可能会成功地将一个布尔值发送到通道中(因为通道是有缓冲的,所以发送不会被阻塞),但是主程序不会等待这个值的接收,而是直接退出了。这样一来,即使 worker goroutine 已经完成了它的工作,主程序也提前退出了,整个程序也就结束了。

Channel Directions

package main  

import "fmt"  

func ping(pings chan<- string, msg string) {  
  pings <- msg  

}  

func pong(pings <-chan string, pongs chan<- string) {  
  msg := <-pings  
  pongs <- msg  
}  
func main() {  
  pings := make(chan string, 1)  
  pongs := make(chan string, 1)  
  ping(pings, "passed message")  
  pong(pings, pongs)  
  fmt.Println(<-pongs)  
}

Select

在 Go 语言中,select 语句用于处理多个通道操作。它类似于 switch 语句,但用于通道操作。select 语句使得一个 Go 程序可以等待多个通道操作同时响应。

  • 多通道操作:select 语句允许在多个通道上等待操作,一次只处理一个准备好的通道操作。

  • 随机选择:如果多个 case 同时准备好,select 会随机选择其中一个来执行。

  • 无阻塞等待:如果没有任何通道准备好,select 会立即执行 default 语句(如果存在)。这种特性使得 select 语句可以用于非阻塞的通道操作。

  • 阻塞等待:如果没有 default 语句,并且所有 case 都没有准备好,select 语句会阻塞,直到其中一个 case 准备好。

package main  

import (  
  "fmt"  
  "time")  

func main() {  
  c1 := make(chan string)  
  c2 := make(chan string)  
  go func() {  
      time.Sleep(time.Second)  
      c1 <- "one"  
  }()  

  go func() {  
      time.Sleep(time.Second * 2)  
      c2 <- "two"  
  }()  

  for i := 0; i < 2; i++ {  
      select {  
      case msg1 := <-c1:  
        fmt.Println("received", msg1)  
      case msg2 := <-c2:  
        fmt.Println("received", msg2)  
      }  

  }  
}

Timeouts

package main  

import (  
  "fmt"  
  "time")  

func main() {  
  c1 := make(chan string, 1)  
  go func() {  
      time.Sleep(time.Second * 2)  
      c1 <- "result 1"  
  }()  

  select {  
  case res := <-c1:  
      fmt.Println(res)  
  case <-time.After(1 * time.Second):  
      fmt.Println("timeout 1")  
  }  

  c2 := make(chan string, 1)  
  go func() {  
      time.Sleep(time.Second * 2)  
      c2 <- "result 2"  
  }()  
  select {  
  case res := <-c2:  
      fmt.Println(res)  
  case <-time.After(3 * time.Second):  
      fmt.Println("timeout 2")  
  }  
}

Non-Blocking Channel Operations

package main  

import "fmt"  

func main() {  
  messages := make(chan string)  
  signals := make(chan bool)  

  select {  
  case msg := <-messages:  
      fmt.Println("received messages", msg)  
  default:  
      fmt.Println("no messages received")  
  }  

  msg := "hi"  
  select {  
  case messages <- msg:  
      fmt.Println("sent message", msg)  
  default:  
      fmt.Println("no message sent")  
  }  

  select {  
  case msg := <-messages:  
      fmt.Println("received messages", msg)  
  case sig := <-signals:  
      fmt.Println("received signal", sig)  
  default:  
      fmt.Println("no activity")  
  }  
}

这里的通道是无缓存的,因此 msg 无法发送到通道中,阻塞。

Closing Channels

package main  

import "fmt"  

func main() {  
  jobs := make(chan int, 5)  
  done := make(chan bool)  

  go func() {  
      for {  
        j, more := <-jobs  
        if more {  
            fmt.Println("received job", j)  
        } else {  
            fmt.Println("received all jobs")  
            done <- true  
            return  
        }  
      }  
  }()  

  for j := 1; j <= 3; j++ {  
      jobs <- j  
      fmt.Println("sent job", j)  
  }  
  close(jobs)  
  fmt.Println("sent all jobs")  

  <-done  
  _, ok := <-jobs  
  fmt.Println("received more jobs:", ok)  
}

这段代码运行结果为:

sent job 1
sent job 2
sent job 3
sent all jobs
received job 1
received job 2
received job 3
received all jobs
received more jobs: false

首先,在主线程中,进入循环,每次打印出 sent job,3 次之后,关闭 jobs 通道,并且打印 sent all jobs,此时,<-done 的作用是阻塞主线程,等待从 done 中接收一个值,在此期间 goroutine 接收到 jobs 的消息,并且打印出 received jobs,3 次之后,received all jobs,并且给 done 复制,此时阻塞继续执行,由于 jobs 已经关闭,因此 ok 为 false,打印 received more jobs: false。

Range over Channels

package main  

import "fmt"  

func main() {  
  queue := make(chan string, 2)  
  queue <- "one"  
  queue <- "two"  
  close(queue)  
  for i := range queue {  
      fmt.Println(i)  
  }  
}

Timers

package main  

import (  
  "fmt"  
  "time")  

func main() {  
  time1 := time.NewTimer(time.Second * 2)  

  <-time1.C  
  fmt.Println("Timer 1 fired")  

  timer2 := time.NewTimer(time.Second)  
  go func() {  
      <-timer2.C  
      fmt.Println("Timer 2 fired")  
  }()  
  stop2 := timer2.Stop()  
  if stop2 {  
      fmt.Println("Timer 2 stopped")  
  }  

  time.Sleep(time.Second * 2)  
}

Tickers

package main  

import (  
  "fmt"  
  "time")  

func main() {  
  ticker := time.NewTicker(500 * time.Millisecond)  
  done := make(chan bool)  

  go func() {  

      for {  
        select {  
        case <-done:  
            return  
        case t := <-ticker.C:  
            fmt.Println("Tick at", t)  

        }  
      }  
  }()  

  time.Sleep(1600 * time.Millisecond)  
  ticker.Stop()  
  done <- true  
  fmt.Println("Ticker Stopped")  

}

与 Timer 的区别在于,tickers are for when you want to do something repeatly

Worker Pools

package main  

import (  
  "fmt"  
  "time")  

func worker(id int, jobs <-chan int, results chan<- int) {  
  for j := range jobs {  
      fmt.Println("worker", id, "started job", j)  
      time.Sleep(time.Second)  
      fmt.Println("worker", id, "finished job", j)  
      results <- j * 2  
  }  
}  
func main() {  
  const numJobs = 5  
  jobs := make(chan int, numJobs)  
  results := make(chan int, numJobs)  

  for w := 1; w <= 3; w++ {  
      go worker(w, jobs, results)  

  }  
  for j := 1; j <= numJobs; j++ {  
      jobs <- j  
  }  
  close(jobs)  
  for a := 1; a <= numJobs; a++ {  
      <-results  
  }  
}

jobs <-chan int, results chan<- int 分别为一个只读和只写的通道,虽然只启动了 3 个 worker 协程,但是向 jobs  通道发送了 5 个任务。这些任务会被这 3 个 worker 协程并发地处理。

WaitGroups

package main  

import (  
  "fmt"  
  "sync"   "time")  

func worker(id int) {  
  fmt.Println("worker starting ", id)  
  time.Sleep(time.Second)  
  fmt.Println("worker done ", id)  
}  

func main() {  
  var wg sync.WaitGroup  

  for i := 1; i <= 5; i++ {  
      wg.Add(1)  
      go func() {  
        defer wg.Done()  
        worker(i)  
      }()  
  }  
  wg.Wait()  
}

使用 waitgroups 来等待所有 goroutines 完成。

Rate Limiting

package main  

import (  
  "fmt"  
  "time")  

func main() {  
  requests := make(chan int, 5)  
  for i := 1; i <= 5; i++ {  
      requests <- i  
  }  
  close(requests)  

  limiter := time.Tick(200 * time.Millisecond)  
  for req := range requests {  
      <-limiter  
      fmt.Println("request", req, time.Now())  
  }  
}

如果想限制速率,可以通过 time.Tick 设置一个 limiter。

Atomic Counters

package main  

import (  
  "fmt"  
  "sync"   "sync/atomic")  

func main() {  

  var ops atomic.Uint64  

  var wg sync.WaitGroup  

  for i := 0; i < 50; i++ {  
      wg.Add(1)  

      go func() {  
        for c := 0; c < 1000; c++ {  

            ops.Add(1)  
        }  

        wg.Done()  
      }()  
  }  

  wg.Wait()  

  fmt.Println("ops:", ops.Load())  
}

使用 load 来更新,线程安全。

Mutexes

package main  

import (  
  "fmt"  
  "sync")  

type Container struct {  
  mu       sync.Mutex  
  counters map[string]int  
}  

func (c *Container) inc(name string) {  

  c.mu.Lock()  
  defer c.mu.Unlock()  
  c.counters[name]++  
}  

func main() {  
  c := Container{  

      counters: map[string]int{"a": 0, "b": 0},  
  }  

  var wg sync.WaitGroup  

  doIncrement := func(name string, n int) {  
      for i := 0; i < n; i++ {  
        c.inc(name)  
      }  
      wg.Done()  
  }  

  wg.Add(3)  
  go doIncrement("a", 10000)  
  go doIncrement("a", 10000)  
  go doIncrement("b", 10000)  

  wg.Wait()  
  fmt.Println(c.counters)  
}

对于更复杂的场景,想要在多线程中安全地操作数据,可以利用 mutex。在获取数据之前,先用 mutex 锁住,再通过 defer 进行 unlock。

Panic

package main  

import "os"  

func main() {  
  panic(" a problem")  

  _, err := os.Create("/tmp/file")  
  if err != nil {  
      panic(err)  
  }  
}

Recover

package main  

import "fmt"  

func myPanic() {  
  panic("a problem")  

}  
func main() {  
  defer func() {  
      if r := recover(); r != nil {  
        fmt.Println("revocered. Error ", r)  
      }  
  }()  
  myPanic()  
  fmt.Println("After mypanic()")  
}

Go 可以通过 recover 函数从 panic 中恢复,可以阻止 panic 中止程序,让它继续执行。例如下面的场景:如果其中一个客户端连接出现严重错误,服务器不希望崩溃。而是希望关闭该连接并继续为其他客户端提供服务。recover 必须在 defer 函数中调用。

Text Templates

package main  

import (  
  "os"  
  "text/template")  

func main() {  

  t1 := template.New("t1")  
  t1, err := t1.Parse("Value is {{.}}n")  
  if err != nil {  
      panic(err)  
  }  

  t1 = template.Must(t1.Parse("Value: {{.}}n"))  

  t1.Execute(os.Stdout, "some text")  
  t1.Execute(os.Stdout, 5)  
  t1.Execute(os.Stdout, []string{  
      "Go",  
      "Rust",  
      "C++",  
      "C#",  
  })  

  Create := func(name, t string) *template.Template {  
      return template.Must(template.New(name).Parse(t))  
  }  

  t2 := Create("t2", "Name: {{.Name}}n")  

  t2.Execute(os.Stdout, struct {  
      Name string  
  }{"Jane Doe"})  

  t2.Execute(os.Stdout, map[string]string{  
      "Name": "Mickey Mouse",  
  })  

  t3 := Create("t3",  
      "{{if . -}} yes {{else -}} no {{end}}n")  
  t3.Execute(os.Stdout, "not empty")  
  t3.Execute(os.Stdout, "")  

  t4 := Create("t4",  
      "Range: {{range .}}{{.}} {{end}}n")  
  t4.Execute(os.Stdout,  
      []string{  
        "Go",  
        "Rust",  
        "C++",  
        "C#",  
      })  
}

展示动态内容或自定义输入。

Regular Expressions

package main  

import (  
  "fmt"  
  "regexp")  

func main() {  
  match, _ := regexp.MatchString("p([a-z]+)ch", "peach")  
  fmt.Println(match)  

  r, _ := regexp.Compile("p([a-z]+)ch")  
  fmt.Println(r.MatchString("peach"))  
  fmt.Println(r.FindString("peach punch"))  
  fmt.Println(r.FindStringIndex("peach punch"))  
  fmt.Println(r.FindStringSubmatch("peach punch"))  
  fmt.Println(r.FindStringSubmatchIndex("peach punch"))  
  fmt.Println(r.FindAllString("peach punch pinch", -1))  
  fmt.Println(r.FindAllString("peach punch pinch", 0))  
  fmt.Println(r.FindAllString("peach punch pinch", 1))  
  fmt.Println(r.FindAllString("peach punch pinch", 2))  
}

使用正则表达式创建全局变量时,最好用 MustCompile ,因为 MustCompile 会返回 panic 而不是返回错误,这使得用于全局变量更安全。

JSON

package main  

import (  
  "encoding/json"  
  "fmt"   "os")  

type response1 struct {  
  Page   int  
  Fruits []string  
}  

type response2 struct {  
  Page   int     `json:"page"`  
  Fruits []string `json:"fruits"`  
}  

func main() {  

  slcD := []string{"apple", "peach", "pear"}  
  slcB, _ := json.Marshal(slcD)  
  fmt.Println(string(slcB))  

  mapD := map[string]int{"apple": 5, "lettuce": 7}  
  mapB, _ := json.Marshal(mapD)  
  fmt.Println(string(mapB))  

  res1D := &response1{  
      Page:   1,  
      Fruits: []string{"apple", "peach", "pear"}}  
  res1B, _ := json.Marshal(res1D)  
  fmt.Println(string(res1B))  

  res2D := &response2{  
      Page:   1,  
      Fruits: []string{"apple", "peach", "pear"}}  
  res2B, _ := json.Marshal(res2D)  
  fmt.Println(string(res2B))  

  byt := []byte(`{"num":6.13,"strs":["a","b"]}`)  

  var dat map[string]interface{}  

  if err := json.Unmarshal(byt, &dat); err != nil {  
      panic(err)  
  }  
  fmt.Println(dat)  

  num := dat["num"].(float64)  
  fmt.Println(num)  

  strs := dat["strs"].([]interface{})  
  str1 := strs[0].(string)  
  fmt.Println(str1)  

  str := `{"page": 1, "fruits": ["apple", "peach"]}`  
  res := response2{}  
  json.Unmarshal([]byte(str), &res)  
  fmt.Println(res)  
  fmt.Println(res.Fruits[0])  

  enc := json.NewEncoder(os.Stdout)  
  d := map[string]int{"apple": 5, "lettuce": 7}  
  enc.Encode(d)  
}

Time

package main  

import (  
  "fmt"  
  "time")  

func main() {  
  p := fmt.Println  

  now := time.Now()  
  p(now)  

  then := time.Date(  
      2009, 11, 17, 20, 34, 58, 651387237, time.UTC)  
  p(then)  

  p(then.Year())  
  p(then.Month())  
  p(then.Day())  
  p(then.Hour())  
  p(then.Minute())  
  p(then.Second())  
  p(then.Nanosecond())  
  p(then.Location())  

  p(then.Weekday())  

  p(then.Before(now))  
  p(then.After(now))  
  p(then.Equal(now))  

  diff := now.Sub(then)  
  p(diff)  

  p(diff.Hours())  
  p(diff.Minutes())  
  p(diff.Seconds())  
  p(diff.Nanoseconds())  

  p(then.Add(diff))  
  p(then.Add(-diff))  
}

Random Numbers

package main  

import (  
  "fmt"  
  "math/rand")  

func main() {  

  fmt.Print(rand.Int(), ",")  
  fmt.Print(rand.Int())  
  fmt.Println()  

  fmt.Println(rand.Float64())  

  fmt.Print((rand.Float64()*5)+5, ",")  
  fmt.Print((rand.Float64() * 5) + 5)  
  fmt.Println()  

}

Number Parsing

package main  

import (  
  "fmt"  
  "strconv")  

func main() {  

  f, _ := strconv.ParseFloat("1.234", 64)  
  fmt.Println(f)  

  i, _ := strconv.ParseInt("123", 0, 64)  
  fmt.Println(i)  

  d, _ := strconv.ParseInt("0x1c8", 0, 64)  
  fmt.Println(d)  

  u, _ := strconv.ParseUint("789", 0, 64)  
  fmt.Println(u)  

  k, _ := strconv.Atoi("135")  
  fmt.Printf("%Tn", k)  
  fmt.Println(k)  

  _, e := strconv.Atoi("wat")  
  fmt.Println(e)  
}

URL Parsing

package main  

import (  
  "fmt"  
  "net"   "net/url")  

func main() {  

  s := "postgres://user:[email protected]:5432/path?k=v#f"  

  u, err := url.Parse(s)  
  if err != nil {  
      panic(err)  
  }  

  fmt.Println(u.Scheme)  

  fmt.Println(u.User)  
  fmt.Println(u.User.Username())  
  p, _ := u.User.Password()  
  fmt.Println(p)  

  fmt.Println(u.Host)  
  host, port, _ := net.SplitHostPort(u.Host)  
  fmt.Println(host)  
  fmt.Println(port)  

  fmt.Println(u.Path)  
  fmt.Println(u.Fragment)  

  fmt.Println(u.RawQuery)  
  m, _ := url.ParseQuery(u.RawQuery)  
  fmt.Println(m)  
  fmt.Println(m["k"][0])  
}

SHA256 Hashes

package main  

import (  
  "crypto/sha256"  
  "fmt")  

func main() {  
  s := "sha256 this string"  
  h := sha256.New()  
  h.Write([]byte(s))  
  bs := h.Sum(nil)  
  fmt.Printf("%x", bs)  
}

Base64 Encoding

package main  

import (  
  b64 "encoding/base64"  
  "fmt")  

func main() {  

  data := "abc123!?$*&()'-=@~"  

  sEnc := b64.StdEncoding.EncodeToString([]byte(data))  
  fmt.Println(sEnc)  

  sDec, _ := b64.StdEncoding.DecodeString(sEnc)  
  fmt.Println(string(sDec))  
  fmt.Println()  

  uEnc := b64.URLEncoding.EncodeToString([]byte(data))  
  fmt.Println(uEnc)  
  uDec, _ := b64.URLEncoding.DecodeString(uEnc)  
  fmt.Println(string(uDec))  
}

Reading Files

package main  

import (  
  "fmt"  
  "os")  

func check(e error) {  
  if e != nil {  
      panic(e)  
  }  
}  

func main() {  
  data, err := os.ReadFile("testfile")  
  check(err)  
  fmt.Print(string(data))  

}

Writing Files

package main  

import (  
  "fmt"  
  "os")  

func check(e error) {  
  if e != nil {  
      panic(e)  
  }  
}  
func main() {  
  d1 := []byte("hellongon")  
  err := os.WriteFile("writefile", d1, 0644)  
  check(err)  
  f, err := os.Create("writefile2")  
  check(err)  
  defer f.Close()  

  d2 := []byte{115, 111, 109, 101, 10}  
  n2, err := f.Write(d2)  
  check(err)  
  fmt.Println("write bytes: ", n2)  

  n3, err := f.WriteString("writesn")  
  check(err)  
  fmt.Println("write bytes: ", n3)  
  f.Sync()  

}

Line Filters

package main  

import (  
  "bufio"  
  "fmt"   "os"   "strings")  

func main() {  
  scanner := bufio.NewScanner(os.Stdin)  
  for scanner.Scan() {  
      ucl := strings.ToUpper(scanner.Text())  
      fmt.Println(ucl)  
  }  

  if err := scanner.Err(); err != nil {  
      fmt.Println(os.Stderr, "error: ", err)  
      os.Exit(1)  
  }  
}

File Paths

package main  

import (  
  "fmt"  
  "path/filepath"   "strings")  

func main() {  
  p := filepath.Join("dir1", "dir2", "filename")  
  fmt.Println("p:", p)  

  fmt.Println(filepath.Join("dir1//", "filename"))  
  fmt.Println(filepath.Join("dir1/../dir1", "filename"))  

  fmt.Println("Dir(p):", filepath.Dir(p))  
  fmt.Println("Base(p):", filepath.Base(p))  

  fmt.Println(filepath.IsAbs("dir/file"))  
  fmt.Println(filepath.IsAbs("C:/a/dir/file"))  

  filename := "config.json"  
  fmt.Println(filepath.Ext(filename))  

  fmt.Println(strings.TrimSuffix(filename, filepath.Ext(filename)))  

}

filepath.Join 会自动删除多余的分隔符等等来进行归一化。

Directories

package main  

import (  
  "fmt"  
  "io/fs"   "os"   "path/filepath")  

func check(e error) {  
  if e != nil {  
      panic(e)  
  }  
}  

func main() {  

  err := os.Mkdir("subdir", 0755)  
  check(err)  

  defer os.RemoveAll("subdir")  

  createEmptyFile := func(name string) {  
      d := []byte("")  
      check(os.WriteFile(name, d, 0644))  
  }  

  createEmptyFile("subdir/file1")  

  err = os.MkdirAll("subdir/parent/child", 0755)  
  check(err)  

  createEmptyFile("subdir/parent/file2")  
  createEmptyFile("subdir/parent/file3")  
  createEmptyFile("subdir/parent/child/file4")  

  c, err := os.ReadDir("subdir/parent")  
  check(err)  

  fmt.Println("Listing subdir/parent")  
  for _, entry := range c {  
      fmt.Println(" ", entry.Name(), entry.IsDir())  
  }  

  err = os.Chdir("subdir/parent/child")  
  check(err)  

  c, err = os.ReadDir(".")  
  check(err)  

  fmt.Println("Listing subdir/parent/child")  
  for _, entry := range c {  
      fmt.Println(" ", entry.Name(), entry.IsDir())  
  }  

  err = os.Chdir("../../..")  
  check(err)  

  fmt.Println("Visiting subdir")  
  err = filepath.WalkDir("subdir", visit)  
}  

func visit(path string, d fs.DirEntry, err error) error {  
  if err != nil {  
      return err  
  }  
  fmt.Println(" ", path, d.IsDir())  
  return nil  
}

os.RemoveAll-->rm -rfos.MkdirAll-->mkdir -pos.Chdir-->cd

Temporary Files and Directories

package main  

import (  
  "fmt"  
  "os"   "path/filepath")  

func check(e error) {  
  if e != nil {  
      panic(e)  
  }  
}  

func main() {  
  f, err := os.CreateTemp("", "sample")  
  check(err)  
  fmt.Println("Temp file name:", f.Name())  
  defer os.Remove(f.Name())  

  _, err = f.Write([]byte("testfile"))  
  check(err)  

  dname, err := os.MkdirTemp("", "sampledir")  
  check(err)  
  fmt.Println("Temp dir name:", dname)  

  defer os.RemoveAll(dname)  
  fname := filepath.Join(dname, "file1")  
  fmt.Println(fname)  
  err = os.WriteFile(fname, []byte{1, 2}, 0644)  
  check(err)  
}

通过 os.CreateTemp 在操作系统默认位置创建临时文件。

Command-Line Arguments

package main  

import (  
  "fmt"  
  "os")  

func main() {  
  argswithprog := os.Args  
  argswithoutprog := os.Args[1:]  
  arg := os.Args[3]  
  fmt.Println(argswithprog)  
  fmt.Println(argswithoutprog)  
  fmt.Println(arg)  
}

Command-Line Flags

package main  

import (  
  "flag"  
  "fmt")  

func main() {  
  wordPtr := flag.String("word", "foo", "a string")  
  numPtr := flag.Int("num", 42, "an int")  
  forkPtr := flag.Bool("fork", false, "a bool")  
  var svar string  
  flag.StringVar(&svar, "svar", "bar", "a string var")  

  flag.Parse()  
  fmt.Println("word:", *wordPtr)  
  fmt.Println("numb:", *numPtr)  
  fmt.Println("fork:", *forkPtr)  
  fmt.Println("svar:", svar)  
  fmt.Println("tail:", flag.Args())  
}

执行结果如下:

PS C:UsersRy4nDesktopgolanggobyexample> .CmdFlags.exe
word: foo
numb: 42
fork: false
svar: bar
tail: []
PS C:UsersRy4nDesktopgolanggobyexample> .CmdFlags.exe -word abc
word: abc
numb: 42
fork: false
svar: bar
tail: []
PS C:UsersRy4nDesktopgolanggobyexample> .CmdFlags.exe -word abc -fork
word: abc
numb: 42
fork: true
svar: bar
tail: []

另外,-h 会获取自动生成的帮助文本内容

Command-Line Subcommands

package main  

import (  
  "flag"  
  "fmt"   "os")  

func main() {  
  fooCmd := flag.NewFlagSet("foo", flag.ExitOnError)  
  fooEnable := fooCmd.Bool("enable", false, "enable")  
  fooName := fooCmd.String("name", "", "name")  

  barCmd := flag.NewFlagSet("bar", flag.ExitOnError)  
  barLevel := barCmd.Int("level", 0, "level")  

  if len(os.Args) < 2 {  
      fmt.Println("expect 'foo' or 'bar' subcommands")  
      os.Exit(1)  
  }  
  switch os.Args[1] {  
  case "foo":  
      fooCmd.Parse(os.Args[2:])  
      fmt.Println("subcommand 'foo'")  
      fmt.Println(" enable:", *fooEnable)  
      fmt.Println(" name:", *fooName)  
      fmt.Println(" tail:", fooCmd.Args())  
  case "bar":  
      barCmd.Parse(os.Args[2:])  
      fmt.Println("subcommand 'bar'")  
      fmt.Println(" level:", *barLevel)  
      fmt.Println(" tail:", barCmd.Args())  
  default:  
      fmt.Println("expected 'foo' or 'bar' subcommands")  
      os.Exit(1)  
  }  
}

Environment Variables

package main  

import (  
  "fmt"  
  "os"   "strings")  

func main() {  
  os.Setenv("FOO", "1")  
  fmt.Println("FOO:", os.Getenv("FOO"))  
  fmt.Println("WQW:", os.Getenv("WQW"))  
  fmt.Println()  
  for _, e := range os.Environ() {  
      pair := strings.SplitN(e, "=", 2)  
      fmt.Println(pair[0], " ", pair[1])  
  }  
}

Logging

package main  

import (  
  "bytes"  
  "fmt"   "log"   "os")  

func main() {  

  log.Println("standard logger")  

  log.SetFlags(log.LstdFlags | log.Lmicroseconds)  
  log.Println("with micro")  

  log.SetFlags(log.LstdFlags | log.Lshortfile)  
  log.Println("with file/line")  

  mylog := log.New(os.Stdout, "my:", log.LstdFlags)  
  mylog.Println("from mylog")  

  mylog.SetPrefix("ohmy:")  
  mylog.Println("from mylog")  

  var buf bytes.Buffer  
  buflog := log.New(&buf, "buf:", log.LstdFlags)  

  buflog.Println("hello")  

  fmt.Print("from buflog:", buf.String())  

}

HTTP Client

package main  

import (  
  "bufio"  
  "fmt"   "net/http")  

func main() {  
  resp, err := http.Get("https://gobyexample.com")  
  if err != nil {  
      panic(err)  
  }  
  defer resp.Body.Close()  

  fmt.Println("status code", resp.Status)  
  scanner := bufio.NewScanner(resp.Body)  
  for i := 0; scanner.Scan() && i < 5; i++ {  
      fmt.Println(scanner.Text())  
  }  
}

HTTP Server

package main  

import (  
  "fmt"  
  "net/http")  

func hello(w http.ResponseWriter, req *http.Request) {  
  fmt.Fprintf(w, "htllon")  

}  
func headers(w http.ResponseWriter, req *http.Request) {  
  for name, headers := range req.Header {  
      for _, h := range headers {  
        fmt.Fprintf(w, "%v:%vn", name, h)  
      }  
  }  
}  

func main() {  
  http.HandleFunc("/hello", hello)  
  http.HandleFunc("/headers", headers)  
  http.ListenAndServe(":8090", nil)  
}

Spawning Processes

package main  

import (  
  "fmt"  
  "io"   "os/exec")  

func main() {  

  dateCmd := exec.Command("date")  

  dateOut, err := dateCmd.Output()  
  if err != nil {  
      panic(err)  
  }  
  fmt.Println("> date")  
  fmt.Println(string(dateOut))  

  _, err = exec.Command("date", "-x").Output()  
  if err != nil {  
      switch e := err.(type) {  
      case *exec.Error:  
        fmt.Println("failed executing:", err)  
      case *exec.ExitError:  
        fmt.Println("command exit rc =", e.ExitCode())  
      default:  
        panic(err)  
      }  
  }  

  grepCmd := exec.Command("grep", "hello")  

  grepIn, _ := grepCmd.StdinPipe()  
  grepOut, _ := grepCmd.StdoutPipe()  
  grepCmd.Start()  
  grepIn.Write([]byte("hello grepngoodbye grep"))  
  grepIn.Close()  
  grepBytes, _ := io.ReadAll(grepOut)  
  grepCmd.Wait()  

  fmt.Println("> grep hello")  
  fmt.Println(string(grepBytes))  

  lsCmd := exec.Command("bash", "-c", "ls -a -l -h")  
  lsOut, err := lsCmd.Output()  
  if err != nil {  
      panic(err)  
  }  
  fmt.Println("> ls -a -l -h")  
  fmt.Println(string(lsOut))  
}

Exec'ing Processes

package main  

import (  
  "os"  
  "os/exec"   "syscall")  

func main() {  

  binary, lookErr := exec.LookPath("ls")  
  if lookErr != nil {  
      panic(lookErr)  
  }  

  args := []string{"ls", "-a", "-l", "-h"}  

  env := os.Environ()  

  execErr := syscall.Exec(binary, args, env)  
  if execErr != nil {  
      panic(execErr)  
  }  
}

spawning external processes:需要一个外部进程来运行 goexec process:需要另一个进程来替换当前的 go 进程

Exit

package main

import (
  "fmt"
  "os"
)

func main() {

  defer fmt.Println("!")

  os.Exit(3)
}

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年4月10日15:36:54
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   gobyexample通关笔记https://cn-sec.com/archives/2636647.html

发表评论

匿名网友 填写信息