golang基础(2)https://developer.aliyun.com/article/1530652
格式化
package main import "fmt" type point struct { x, y int } func main() { s := "hello" n := 123 p := point{1, 2} fmt.Println(s, n) // hello 123 fmt.Println(p) // {1 2} fmt.Printf("s=%v\n", s) // s=hello fmt.Printf("n=%v\n", n) // n=123 fmt.Printf("p=%v\n", p) // p={1 2} fmt.Printf("p=%+v\n", p) // p={x:1 y:2} fmt.Printf("p=%#v\n", p) // p=main.point{x:1, y:2} f := 3.141592653 fmt.Println(f) // 3.141592653 fmt.Printf("%.2f\n", f) // 3.14 }
json
package main import ( "encoding/json" "fmt" ) type userInfo struct { Name string Age int `json:"age"` Hobby []string } func main() { a := userInfo{Name: "wang", Age: 18, Hobby: []string{"Golang", "TypeScript"}} buf, err := json.Marshal(a) if err != nil { panic(err) } fmt.Println(buf) // [123 34 78 97...] fmt.Println(string(buf)) // {"Name":"wang","age":18,"Hobby":["Golang","TypeScript"]} buf, err = json.MarshalIndent(a, "", "\t") if err != nil { panic(err) } fmt.Println(string(buf)) var b userInfo err = json.Unmarshal(buf, &b) if err != nil { panic(err) } fmt.Printf("%#v\n", b) // main.userInfo{Name:"wang", Age:18, Hobby:[]string{"Golang", "TypeScript"}} }
json.MarshalIndent作用
ChatGPT
json.MarshalIndent
是 Go 语言标准库中用于将数据结构序列化为 JSON 格式并添加缩进的函数。它将 Go 的数据结构转换为 JSON 字节切片,并根据指定的缩进格式对 JSON 进行格式化,使 JSON 数据在显示时更易读。
函数签名:
goCopy code func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
v
: 要序列化为 JSON 的数据结构,通常为一个 Go 的数据类型,例如 struct、map、slice 等。prefix
: 缩进前缀,用于在每一行缩进级别之前添加的前缀字符串。一般设置为空格或制表符来实现缩进效果。indent
: 每一行缩进的字符串,通常由空格或制表符组成。
json.MarshalIndent
会根据 v
中的数据结构生成一个带有缩进格式的 JSON 字节切片。
示例:
goCopy codepackage main import ( "encoding/json" "fmt" ) type Person struct { Name string Age int Country string } func main() { person := Person{ Name: "John", Age: 30, Country: "USA", } // 使用 json.MarshalIndent 将结构体序列化为带有缩进格式的 JSON jsonData, err := json.MarshalIndent(person, "", " ") if err != nil { fmt.Println("Error marshaling JSON:", err) return } fmt.Println(string(jsonData)) }
在上面的例子中,我们定义了一个 Person
结构体,然后使用 json.MarshalIndent
将其序列化为带有缩进格式的 JSON。输出结果将是类似于下面的内容:
jsonCopy code{ "Name": "John", "Age": 30, "Country": "USA" }
这样的格式化使得生成的 JSON 数据更具可读性,并且更容易在调试和查看 JSON 数据时进行理解。
time
package main import ( "fmt" "time" ) func main() { now := time.Now() fmt.Println(now) // 2022-03-27 18:04:59.433297 +0800 CST m=+0.000087933 t := time.Date(2022, 3, 27, 1, 25, 36, 0, time.UTC) t2 := time.Date(2022, 3, 27, 2, 30, 36, 0, time.UTC) fmt.Println(t) // 2022-03-27 01:25:36 +0000 UTC fmt.Println(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute()) // 2022 March 27 1 25 fmt.Println(t.Format("2006-01-02 15:04:05")) // 2022-03-27 01:25:36 diff := t2.Sub(t) fmt.Println(diff) // 1h5m0s fmt.Println(diff.Minutes(), diff.Seconds()) // 65 3900 t3, err := time.Parse("2006-01-02 15:04:05", "2022-03-27 01:25:36") if err != nil { panic(err) } fmt.Println(t3 == t) // true fmt.Println(now.Unix()) // 1648738080 }
字符串转换
package main import ( "fmt" "strconv" ) func main() { f, _ := strconv.ParseFloat("1.234", 64) fmt.Println(f) // 1.234 n, _ := strconv.ParseInt("111", 10, 64) fmt.Println(n) // 111 n, _ = strconv.ParseInt("0x1000", 0, 64) fmt.Println(n) // 4096 n2, _ := strconv.Atoi("123") fmt.Println(n2) // 123 n2, err := strconv.Atoi("AAA") fmt.Println(n2, err) // 0 strconv.Atoi: parsing "AAA": invalid syntax }
env
package main import ( "fmt" "os" "os/exec" ) func main() { // go run example/20-env/main.go a b c d fmt.Println(os.Args) // [/var/folders/8p/n34xxfnx38dg8bv_x8l62t_m0000gn/T/go-build3406981276/b001/exe/main a b c d] fmt.Println(os.Getenv("PATH")) // /usr/local/go/bin... fmt.Println(os.Setenv("AA", "BB")) buf, err := exec.Command("grep", "127.0.0.1", "/etc/hosts").CombinedOutput() if err != nil { panic(err) } fmt.Println(string(buf)) // 127.0.0.1 localhost }
协程
cpu本身可以保存状态,且不需要切换
实战
猜数游戏
package main import ( "bufio" "fmt" "math/rand" "os" "strconv" "strings" "time" ) func main() { maxNum := 100 rand.Seed(time.Now().UnixNano()) secretNumber := rand.Intn(maxNum) fmt.Println("the secret is", secretNumber) fmt.Println("please input your guess") //把输入文件转成一个只读的流 reader := bufio.NewReader(os.Stdin) //读取用户输入,直到遇到换行符为止 for { input, err := reader.ReadString('\n') if err != nil { fmt.Println("an error occured while reading input , Please try again", err) continue } input = strings.TrimSuffix(input, "\r\n") guess, err := strconv.Atoi(input) if err != nil { fmt.Println("Invaild input", err) continue } fmt.Println("Your gusee is", guess) if guess > secretNumber { fmt.Println("your input is bugger ") } else if guess < secretNumber { fmt.Println("your input is smaller") } else { fmt.Println("correct") break } } }
是的,Go标准库中还有一些与字符串处理相关的函数,其中一些与 strings.TrimSuffix
类似,用于处理字符串的前缀和后缀。以下是其中几个常用的函数:
strings.TrimPrefix(s, prefix string) string
: 去除字符串开头的指定前缀,返回新的字符串。如果原始字符串以指定前缀开头,则去除该前缀;否则,原始字符串保持不变。strings.HasPrefix(s, prefix string) bool
: 检查字符串是否以指定前缀开头,返回一个布尔值。如果字符串以指定前缀开头,返回true
,否则返回false
。strings.HasSuffix(s, suffix string) bool
: 检查字符串是否以指定后缀结尾,返回一个布尔值。如果字符串以指定后缀结尾,返回true
,否则返回false
。strings.Trim(s string, cutset string) string
: 去除字符串开头和结尾的指定字符集合(cutset)中包含的字符,返回新的字符串。如果 cutset 为空,则会去除字符串开头和结尾的空白字符。strings.TrimSpace(s string) string
: 去除字符串开头和结尾的空白字符,返回新的字符串。
这些函数在处理字符串时非常有用,特别是在需要对字符串进行预处理或清理时。使用这些函数可以使字符串处理代码更加简洁和易读。记住,在处理字符串时,要注意处理 Unicode 字符和特殊情况,以确保代码的正确性和鲁棒性。
网络请求
package main import ( "bytes" "encoding/json" "fmt" "os" "io" "log" "net/http" ) type AutoGenerated struct { Rc int `json:"rc"` Wiki struct { } `json:"wiki"` Dictionary struct { Entry string `json:"entry"` Explanations []string `json:"explanations"` Related []interface{} `json:"related"` Source string `json:"source"` Prons struct { } `json:"prons"` Type string `json:"type"` } `json:"dictionary"` } type DictRequest struct { TransType string `json:"trans_type"` Source string `json:"source"` UserId string `json:"user_id"` } func main() { if len(os.Args) != 2 { fmt.Fprint(os.Stderr, `usage: simpleDict WORD example:simpleDict hellp`) os.Exit(1) } word := os.Args[1] query(word) } func query(word string) { client := &http.Client{} // var data = strings.NewReader(`{"trans_type":"zh2en","source":"你好"}`) request := DictRequest{TransType: "zh2en", Source: word} buf, err := json.Marshal(request) if err != nil { log.Fatal(err) } //因为json.Marshal返回的是一个byte数组 var data = bytes.NewReader(buf) //因为这个参数可能是从文件读取的可能很大很大,所以需要是流 req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data) if err != nil { log.Fatal(err) } req.Header.Set("authority", "api.interpreter.caiyunai.com") req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36") req.Header.Set("app-name", "xy") req.Header.Set("content-type", "application/json;charset=UTF-8") req.Header.Set("accept", "application/json, text/plain, */*") req.Header.Set("device-id", "9395fef18b8c40f79517da2f52a54705") req.Header.Set("os-type", "web") req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi") req.Header.Set("origin", "https://fanyi.caiyunapp.com") req.Header.Set("sec-fetch-site", "cross-site") req.Header.Set("sec-fetch-mode", "cors") req.Header.Set("sec-fetch-dest", "empty") req.Header.Set("referer", "https://fanyi.caiyunapp.com/") req.Header.Set("accept-language", "zh-CN,zh;q=0.9") resp, err := client.Do(req) if err != nil { log.Fatal(err) } //关闭流不然会泄露, defer resp.Body.Close() //得到的bodytext是字节数组 bodyText, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } if resp.StatusCode != 200 { log.Fatal("bad status", resp.StatusCode, "body", string(bodyText)) } //字符串输出 // fmt.Printf("%s\n", bodyText) var dicresponce AutoGenerated err = json.Unmarshal(bodyText, &dicresponce) if err != nil { log.Fatal(err) } fmt.Printf("%#v\n", dicresponce) }
这是一个简单的函数 process
,它接受一个网络连接 conn
作为参数,并对这个连接进行读取和写入操作。让我们逐步解析这个函数:
func process(conn net.Conn) {
定义了一个名为process
的函数,它接受一个net.Conn
类型的参数conn
,该参数代表网络连接。defer conn.Close()
使用defer
关键字延迟执行conn.Close()
,确保在函数执行完毕后关闭网络连接。defer
关键字会使conn.Close()
在process
函数的末尾执行,无论函数是正常返回还是因为错误而退出,都会执行该语句来关闭连接。reader := bufio.NewReader()
创建一个bufio.Reader
类型的对象reader
,用于从网络连接中读取数据。但在这里,创建bufio.Reader
时没有传递参数,因此这个reader
并未与指定的网络连接conn
关联,应该修改为reader := bufio.NewReader(conn)
。for {
进入一个无限循环,不断从reader
中读取字节并将其写入连接conn
。b, err := reader.ReadByte()
使用ReadByte()
方法从reader
中读取一个字节。ReadByte()
返回两个值,一个是读取的字节b
,另一个是可能出现的错误err
。if err != nil { break }
检查读取操作是否发生错误,如果出现错误,退出循环,跳出for
循环。_, err = conn.Write([]byte{b})
将刚刚读取的字节b
通过conn.Write()
方法写入连接conn
。Write()
方法返回两个值,一个是写入的字节数,另一个是可能出现的错误err
。if err != nil { break }
检查写入操作是否发生错误,如果出现错误,退出循环,跳出for
循环。}
循环会持续进行,不断读取字节并将其写入连接,直到发生读取或写入错误,导致循环终止。
总体来说,这个函数的目的是将从网络连接中读取的数据逐字节原样写回同一个连接。它将连接作为参数传递,然后在一个无限循环中读取连接的内容,并将每个字节再写回该连接。当读取或写入操作发生错误时,函数会关闭连接并终止。注意在修改 bufio.NewReader()
为 bufio.NewReader(conn)
之后,这个函数将能够正常地工作。
在 Go 语言中,defer
关键字用于延迟(defer)函数的执行,使函数在当前函数执行完成后才会被调用。无论函数是正常返回还是遇到错误导致异常退出,defer
关键字都会确保它指定的函数会被执行,类似于其他编程语言中的 “finally” 块。
defer
的作用如下:
- 延迟函数的执行:使用
defer
关键字可以将函数调用推迟到包含defer
语句的函数返回之后执行。这在需要确保某些资源在函数执行完毕后得到释放时非常有用,例如关闭文件句柄、释放锁、关闭数据库连接等。 - 逆序执行:如果一个函数中有多个
defer
语句,它们会按照后进先出(LIFO)的顺序执行,即最后一个defer
语句会最先执行,而第一个defer
语句会最后执行。 - 避免忘记资源释放:使用
defer
可以帮助避免因为遗漏释放资源而导致的内存泄漏或其他资源泄漏问题。由于defer
会在函数退出时执行,因此可以确保在函数执行完毕后及时释放资源。
示例:
goCopy codepackage main import ( "fmt" "os" ) func main() { file, err := os.Open("example.txt") if err != nil { fmt.Println("Error opening file:", err) return } defer file.Close() // 在函数返回时关闭文件 // 使用文件进行一些操作,比如读取数据等 // 函数执行完毕时,defer语句会执行,文件会被关闭 }
在上面的例子中,通过 defer file.Close()
,无论函数是否正常返回,file.Close()
都会在函数返回时被调用,确保文件句柄被及时关闭。
总结:defer
是 Go 语言中一种方便的机制,用于处理资源释放、清理等操作,使得代码更加清晰、健壮,同时避免了忘记释放资源的问题。
io.ReadAl
io.ReadAll
是 Go 语言标准库中的一个函数,它的作用是从输入流(io.Reader)中读取所有数据并返回一个字节切片([]byte)表示读取的内容。
函数签名:
goCopy code func ReadAll(r io.Reader) ([]byte, error)
参数 r
是一个实现了 io.Reader
接口的对象,可以是文件、网络连接、内存缓冲区等等。io.Reader
接口包含了读取数据的基本方法。
io.ReadAll
会读取 r
中的所有数据,直到遇到文件结束符(EOF)为止,并将读取的内容存储在一个字节切片中返回。同时,它也会返回可能出现的错误(如果有的话)。
使用 io.ReadAll
的常见场景是读取小文件或读取来自网络连接等的数据。请注意,对于非常大的数据流,io.ReadAll
可能不是最佳的选择,因为它会将整个数据流读取到内存中,可能导致内存消耗较大。在处理大型数据流时,最好使用逐块读取的方式。
示例:
goCopy codepackage main import ( "fmt" "io" "os" ) func main() { file, err := os.Open("example.txt") if err != nil { fmt.Println("Error opening file:", err) return } defer file.Close() data, err := io.ReadAll(file) if err != nil { fmt.Println("Error reading file:", err) return } fmt.Println("File contents:") fmt.Println(string(data)) }
在上面的例子中,我们打开一个名为 “example.txt” 的文件,并使用 io.ReadAll
将文件的所有内容读取到 data
变量中,最后打印出文件的内容。
socket5代理
golang基础(4)https://developer.aliyun.com/article/1530658