27 篇文章
🎉🎉🎉 哈喽,你好!!欢迎访问本站.
Go 错误处理
Go 错误处理 一、错误 在Go中有一部分函数总是能成功的运行。比如strings.Contains和strconv.FormatBool函数;对于大部分函数而言,永远无法确保能否成功运行。 Go 语言通过内置的错误接口提供了非常简单的错误处理机制。 error类型是一个接口类型,这是它的定义: 1 2 3 type error interface { Error() string } 我们可以在编码中通过实现 error 接口类型来生成错误信息。 函数通常在最后的返回值中返回错误信息。使用errors.New 可返回一个错误信息: 1 2 3 4 5 6 func Sqrt(f float64) (float64, error) { if f < 0 { return 0, errors.New("math: square root of negative number") } // 实现 } 这里有一个错误处理的例子:
go并发编程
go并发编程 一、协程(Goroutines) 在Go语言中,每一个并发的执行单元叫作一个goroutine。,我们只需要通过 go 关键字来开启 goroutine 即可。goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。 goroutine 语法格式: 1 go 函数名( 参数列表 ) 示例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package main import "fmt" func f(from string) { for i := 0; i < 3; i++ { fmt.Println(from, ":", i) } } func main() { // 假设我们有一个函数叫做 f(s)。 // 我们使用一般的方式调并同时运行。 f("direct") // 使用 go f(s) 在一个 Go 协程中调用这个函数。 // 这个新的 Go 协程将会并行的执行这个函数调用。 go f("goroutine") // 你也可以为匿名函数启动一个 Go 协程。 go func(msg string) { fmt.Println(msg) }("going") // 现在这两个 Go 协程在独立的 Go 协程中异步的运行,所以我们需要等它们执行结束。 // 这里的 Scanln 代码需要我们在程序退出前按下任意键结束。 var input string fmt.Scanln(&input) fmt.Println("done") // 当我们运行这个程序时,将首先看到阻塞式调用的输出,然后是两个 Go 协程的交替输出。 // 这种交替的情况表示 Go 运行时是以异步的方式运行协程的。 } 二、通道(channel) 如果说goroutine是Go语言程序的并发体的话,那么channels则是它们之间的通信机制。通道(channel)是用来传递数据的一个数据结构。
golang常用方法
golang常用方法 字符串函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package main import s "strings" import "fmt" // 我们给 fmt.Println 一个短名字的别名,我们随后将会经常用到。 var p = fmt.Println // 标准库的 strings 包提供了很多有用的字符串相关的函数。 // 这里是一些用来让你对这个包有个初步了解的例子。 func main() { // 这是一些 strings 中的函数例子。 // 注意他们都是包中的函数,不是字符串对象自身的方法,这意味着我们需要考虑在调用时传递字符作为第一个参数进行传递。 p("Contains: ", s.Contains("test", "es")) p("Count: ", s.Count("test", "t")) p("HasPrefix: ", s.HasPrefix("test", "te")) p("HasSuffix: ", s.HasSuffix("test", "st")) p("Index: ", s.Index("test", "e")) p("Join: ", s.Join([]string{"a", "b"}, "-")) p("Repeat: ", s.Repeat("a", 5)) p("Replace: ", s.Replace("foo", "o", "0", -1)) p("Replace: ", s.Replace("foo", "o", "0", 1)) p("Split: ", s.Split("a-b-c-d-e", "-")) p("ToLower: ", s.ToLower("TEST")) p("ToUpper: ", s.ToUpper("test")) // 你可以在 strings包文档中找到更多的函数 p() // 虽然不是 strings 的一部分,但是仍然值得一提的是获取字符串长度和通过索引获取一个字符的机制。 p("Len: ", len("hello")) p("Char:", "hello"[1]) } 字符串格式化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 package main import "fmt" import "os" type point struct { x, y int } func main() { // Go 为常规 Go 值的格式化设计提供了多种打印方式。例如,这里打印了 point 结构体的一个实例。 p := point{1, 2} fmt.Printf("%v\n", p) // 如果值是一个结构体,%+v 的格式化输出内容将包括结构体的字段名。 fmt.Printf("%+v\n", p) // %#v 形式则输出这个值的 Go 语法表示。例如,值的运行源代码片段。 fmt.Printf("%#v\n", p) // 需要打印值的类型,使用 %T。 fmt.Printf("%T\n", p) // 格式化布尔值是简单的。 fmt.Printf("%t\n", true) // 格式化整形数有多种方式,使用 %d进行标准的十进制格式化。 fmt.Printf("%d\n", 123) // 这个输出二进制表示形式。 fmt.Printf("%b\n", 14) // 这个输出给定整数的对应字符。 fmt.Printf("%c\n", 33) // %x 提供十六进制编码。 fmt.Printf("%x\n", 456) // 对于浮点型同样有很多的格式化选项。使用 %f 进行最基本的十进制格式化。 fmt.Printf("%f\n", 78.9) // %e 和 %E 将浮点型格式化为(稍微有一点不同的)科学技科学记数法表示形式。 fmt.Printf("%e\n", 123400000.0) fmt.Printf("%E\n", 123400000.0) // 使用 %s 进行基本的字符串输出。 fmt.Printf("%s\n", "\"string\"") // 像 Go 源代码中那样带有双引号的输出,使用 %q。 fmt.Printf("%q\n", "\"string\"") // 和上面的整形数一样,%x 输出使用 base-16 编码的字符串,每个字节使用 2 个字符表示。 fmt.Printf("%x\n", "hex this") // 要输出一个指针的值,使用 %p。 fmt.Printf("%p\n", &p) // 当输出数字的时候,你将经常想要控制输出结果的宽度和精度,可以使用在 % 后面使用数字来控制输出宽度。 // 默认结果使用右对齐并且通过空格来填充空白部分。 fmt.Printf("|%6d|%6d|\n", 12, 345) // 你也可以指定浮点型的输出宽度,同时也可以通过 宽度.精度 的语法来指定输出的精度。 fmt.Printf("|%6.2f|%6.2f|\n", 1.2, 3.45) // 要左对齐,使用 - 标志。 fmt.Printf("|%-6.2f|%-6.2f|\n", 1.2, 3.45) // 你也许也想控制字符串输出时的宽度,特别是要确保他们在类表格输出时的对齐。 // 这是基本的右对齐宽度表示。 fmt.Printf("|%6s|%6s|\n", "foo", "b") // 要左对齐,和数字一样,使用 - 标志。 fmt.Printf("|%-6s|%-6s|\n", "foo", "b") // 到目前为止,我们已经看过 Printf了,它通过 os.Stdout输出格式化的字符串。 // Sprintf 则格式化并返回一个字符串而不带任何输出。 s := fmt.Sprintf("a %s", "string") fmt.Println(s) // 你可以使用 Fprintf 来格式化并输出到 io.Writers而不是 os.Stdout。 fmt.Fprintf(os.Stderr, "an %s\n", "error") } 数字转换 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package main import "strconv" import "fmt" // 从字符串中解析数字在很多程序中是一个基础常见的任务,在Go 中是这样处理的。 func main() { // 内置的 strconv 包提供了数字解析功能。 // 使用 ParseFloat 解析浮点数,这里的 64 表示表示解析的数的位数。 f, _ := strconv.ParseFloat("1.234", 64) fmt.Println(f) // 在使用 ParseInt 解析整形数时,例子中的参数 0 表示自动推断字符串所表示的数字的进制。 // 64 表示返回的整形数是以 64 位存储的。 i, _ := strconv.ParseInt("123", 0, 64) fmt.Println(i) // ParseInt 会自动识别出十六进制数。 d, _ := strconv.ParseInt("0x1c8", 0, 64) fmt.Println(d) // ParseUint 也是可用的。 u, _ := strconv.ParseUint("789", 0, 64) fmt.Println(u) // Atoi 是一个基础的 10 进制整型数转换函数。 k, _ := strconv.Atoi("135") fmt.Println(k) // 在输入错误时,解析函数会返回一个错误。 _, e := strconv.Atoi("wat") fmt.Println(e) } 时间函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 package main import "fmt" import "time" func main() { p := fmt.Println // 得到当前时间。 now := time.Now() p(now) // 通过提供年月日等信息,你可以构建一个 time。时间总是关联着位置信息,例如时区。 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()) // 输出是星期一到日的 Weekday 也是支持的。 p(then.Weekday()) // 这些方法来比较两个时间,分别测试一下是否是之前,之后或者是同一时刻,精确到秒。 p(then.Before(now)) p(then.After(now)) p(then.Equal(now)) // 方法 Sub 返回一个 Duration 来表示两个时间点的间隔时间。 diff := now.Sub(then) p(diff) // 我们计算出不同单位下的时间长度值。 p(diff.Hours()) p(diff.Minutes()) p(diff.Seconds()) p(diff.Nanoseconds()) // 你可以使用 Add 将时间后移一个时间间隔,或者使用一个 - 来将时间前移一个时间间隔。 p(then.Add(diff)) p(then.Add(-diff)) p("################") // 格式化 // 这里是一个基本的按照 RFC3339 进行格式化的例子,使用对应模式常量。 t := time.Now() p(t.Format(time.RFC3339)) // 时间解析使用同 Format 相同的形式值。 t1, e := time.Parse( time.RFC3339, "2012-11-01T22:08:41+00:00") p(t1) // ormat 和 Parse 使用基于例子的形式来决定日期格式, // 一般你只要使用 time 包中提供的模式常量就行了,但是你也可以实现自定义模式。 // 模式必须使用时间 Mon Jan 2 15:04:05 MST 2006来指定给定时间/字符串的格式化/解析方式。 // 时间一定要按照如下所示:2006为年,15 为小时,Monday 代表星期几,等等。 p(t.Format("3:04PM")) p(t.Format("Mon Jan _2 15:04:05 2006")) p(t.Format("2006-01-02T15:04:05.999999-07:00")) form := "3 04 PM" t2, e := time.Parse(form, "8 41 PM") p(t2) // 对于纯数字表示的时间,你也可以使用标准的格式化字符串来提出出时间值得组成。 fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second()) // Parse 函数在输入的时间格式不正确是会返回一个错误。 ansic := "Mon Jan _2 15:04:05 2006" _, e = time.Parse(ansic, "8:41PM") p(e) } JSON转换 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 package main import "encoding/json" import "fmt" import "os" // 下面我们将使用这两个结构体来演示自定义类型的编码和解码。 type Response1 struct { Page int Fruits []string } type Response2 struct { Page int `json:"page"` Fruits []string `json:"fruits"` } func main() { // 首先我们来看一下基本数据类型到 JSON 字符串的编码过程。这里是一些原子值的例子。 bolB, _ := json.Marshal(true) fmt.Println(string(bolB)) intB, _ := json.Marshal(1) fmt.Println(string(intB)) fltB, _ := json.Marshal(2.34) fmt.Println(string(fltB)) strB, _ := json.Marshal("gopher") fmt.Println(string(strB)) // 这里是一些切片和 map 编码成 JSON 数组和对象的例子。 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)) // JSON 包可以自动的编码你的自定义类型。 // 编码仅输出可导出的字段,并且默认使用他们的名字作为 JSON 数据的键。 res1D := &Response1{ Page: 1, Fruits: []string{"apple", "peach", "pear"}} res1B, _ := json.Marshal(res1D) fmt.Println(string(res1B)) // 你可以给结构字段声明标签来自定义编码的 JSON 数据键名称。 // 在上面 Response2 的定义可以作为这个标签这个的一个例子。 res2D := &Response2{ Page: 1, Fruits: []string{"apple", "peach", "pear"}} res2B, _ := json.Marshal(res2D) fmt.Println(string(res2B)) // 现在来看看解码 JSON 数据为 Go 值的过程。 // 这里是一个普通数据结构的解码例子。 byt := []byte(`{"num":6.13,"strs":["a","b"]}`) // 我们需要提供一个 JSON 包可以存放解码数据的变量。 // 这里的 map[string]interface{} 将保存一个 string 为键,值为任意值的map。 var dat map[string]interface{} // 这里就是实际的解码和相关的错误检查。 if err := json.Unmarshal(byt, &dat); err != nil { panic(err) } fmt.Println(dat) // 为了使用解码 map 中的值,我们需要将他们进行适当的类型转换。 // 例如这里我们将 num 的值转换成 float64类型。 num := dat["num"].(float64) fmt.Println(num) // 访问嵌套的值需要一系列的转化。 strs := dat["strs"].([]interface{}) str1 := strs[0].(string) fmt.Println(str1) // 我们也可以解码 JSON 值到自定义类型。 // 这个功能的好处就是可以为我们的程序带来额外的类型安全加强,并且消除在访问数据时的类型断言。 str := `{"page": 1, "fruits": ["apple", "peach"]}` res := Response2{} json.Unmarshal([]byte(str), &res) fmt.Println(res) fmt.Println(res.Fruits[0]) // 在上面的例子中,我们经常使用 byte 和 string 作为使用标准输出时数据和 JSON 表示之间的中间值。 // 我们也可以和os.Stdout 一样,直接将 JSON 编码直接输出至 os.Writer流中,或者作为 HTTP 响应体。 enc := json.NewEncoder(os.Stdout) d := map[string]int{"apple": 5, "lettuce": 7} enc.Encode(d) } 文件写入 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package main import ( "bufio" "fmt" "io/ioutil" "os" ) // Go 写文件和我们前面看过的读操作有着相似的方式。 // 读取文件需要经常进行错误检查,这个帮助方法可以精简下面的错误检查过程。 func check(e error) { if e != nil { panic(e) } } func main() { d1 := []byte("hello\ngo\n") // 开始,这里是展示如写入一个字符串(或者只是一些字节)到一个文件。 err := ioutil.WriteFile("D:/study/dat1", d1, 0644) check(err) // 对于更细粒度的写入,先打开一个文件。 f, err := os.Create("D:/study/dat2") check(err) // 打开文件后,习惯立即使用 defer 调用文件的 Close操作。 defer f.Close() // 你可以写入你想写入的字节切片 d2 := []byte{115, 111, 109, 101, 10} n2, err := f.Write(d2) check(err) fmt.Printf("wrote %d bytes\n", n2) // WriteString 也是可用的。 n3, err := f.WriteString("writes\n") fmt.Printf("wrote %d bytes\n", n3) // 调用 Sync 来将缓冲区的信息写入磁盘。 f.Sync() // bufio 提供了和我们前面看到的带缓冲的读取器一样的带缓冲的写入器。 w := bufio.NewWriter(f) n4, err := w.WriteString("buffered\n") fmt.Printf("wrote %d bytes\n", n4) // 使用 Flush 来确保所有缓存的操作已写入底层写入器。 w.Flush() }
golang的指针 结构体 接口
golang的指针\结构体\接口 一、什么是指针 C语言里,变量存放在内存中,而内存其实就是一组有序字节组成的数组,每个字节有唯一的内存地址。CPU 通过内存寻址对存储在内存中的某个指定数据对象的地址进行定位。这里,数据对象是指存储在内存中的一个指定数据类型的数值或字符串,它们都有一个自己的地址,而指针便是保存这个地址的变量。也就是说:指针是一种保存变量地址的变量。 img 二、Go 指针 指针如何定义: 1 2 var ip *int /* 指向整型*/ var fp *float32 /* 指向浮点型 */ 指针使用流程: 定义指针变量。 为指针变量赋值。 访问指针变量中指向地址的值。 示例:
golang函数介绍
golang函数介绍 这里也比较简单,为什么都很简单呢~!~上代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 package main import "fmt" func main() { // hello world fmt.Println("hello world") // 1. 加法 res := plus(1, 2) fmt.Println("1+2 =", res) res = plusPlus(1, 2, 3) fmt.Println("1+2+3 =", res) // 2. 多值返回 // 这里我们通过多赋值 操作来使用这两个不同的返回值。 a, b := vals() fmt.Println(a) fmt.Println(b) // 如果你仅仅想返回值的一部分的话,你可以使用空白定义符 _。 _, c := vals() fmt.Println(c) // 3. 可变参数 // 变参函数使用常规的调用方式,除了参数比较特殊。 sum(1, 2) sum(1, 2, 3) // 如果你的 slice 已经有了多个值,想把它们作为变参使用,你要这样调用 func(slice...)。 nums := []int{1, 2, 3, 4} sum(nums...) // 4. 闭包 // 我们调用 intSeq 函数,将返回值(也是一个函数)赋给nextInt。 // 这个函数的值包含了自己的值 i,这样在每次调用 nextInt 时都会更新 i 的值。 nextInt := intSeq() // 通过多次调用 nextInt 来看看闭包的效果。 fmt.Println(nextInt()) fmt.Println(nextInt()) fmt.Println(nextInt()) // 为了确认这个状态对于这个特定的函数是唯一的,我们重新创建并测试一下。 newInts := intSeq() fmt.Println(newInts()) // 5. 递归 fmt.Println(fact(7)) } // 函数 // 这里是一个函数,接受两个 int 并且以 int 返回它们的和 func plus(a int, b int) int { // Go 需要明确的返回值,例如,它不会自动返回最后一个表达式的值 return a + b } // (int, int) 在这个函数中标志着这个函数返回 2 个 int。 func plusPlus(a, b, c int) int { return a + b + c } // 多返回值函数 func vals() (int, int) { return 3, 7 } // 变参函数 func sum(nums ...int) { fmt.Print(nums, " ") total := 0 for _, num := range nums { total += num } fmt.Println(total) } // 闭包 // 这个 intSeq 函数返回另一个在 intSeq 函数体内定义的匿名函数。 // 这个返回的函数使用闭包的方式 隐藏 变量 i。 func intSeq() func() int { i := 0 return func() int { i += 1 return i } } // 递归 // face 函数在到达 face(0) 前一直调用自身。 func fact(n int) int { if n == 0 { return 1 } return n * fact(n-1) }