介绍go中的指针, 字符串和字符, 结构体, 方法, 接口, 枚举类型和内联结构体
Pointers Go 支持指针,允许在程序中传递对值和记录的引用。
pointers.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 30 31 package mainimport "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) }
log 1 2 3 4 5 $ go run pointers.go initial: 1 zeroval: 1 zeroptr: 0 pointer: 0x42131100
Zeroval 不改变 main 中的 i,但 zeroptr 改变了,因为它引用了该变量的内存地址。
Strings and Runes Go 字符串是只读的字节片段。Go 语言和标准库将字符串作为以 UTF-8 编码的文本容器进行特殊处理。在其他语言中,字符串是由 "字符 "组成的。在 Go 中,"字符 "的概念被称为 "符文"--它是一个整数,代表一个 Unicode 代码点。这篇 Go 博文很好地介绍了这一主题。
strings-and-runes.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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 package mainimport ( "fmt" "unicode/utf8" ) func main () { const s = "สวัสดี" fmt.Println("Len:" , len (s)) for i := 0 ; i < len (s); i++ { fmt.Printf("%x " , s[i]) } fmt.Println() fmt.Println("Rune count:" , utf8.RuneCountInString(s)) for idx, runeValue := range s { fmt.Printf("%#U starts at %d\n" , runeValue, idx) } fmt.Println("\nUsing DecodeRuneInString" ) for i, w := 0 , 0 ; i < len (s); i += w { runeValue, width := utf8.DecodeRuneInString(s[i:]) fmt.Printf("%#U starts at %d\n" , runeValue, i) w = width examineRune(runeValue) } } func examineRune (r rune ) { if r == 't' { fmt.Println("found tee" ) } else if r == 'ส' { fmt.Println("found so sua" ) } }
log 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 $ go run strings-and-runes.go Len: 18 e0 b8 aa e0 b8 a7 e0 b8 b1 e0 b8 aa e0 b8 94 e0 b8 b5 Rune count: 6 U+0E2A 'ส' starts at 0 U+0E27 'ว' starts at 3 U+0E31 'ั' starts at 6 U+0E2A 'ส' starts at 9 U+0E14 'ด' starts at 12 U+0E35 'ี' starts at 15 Using DecodeRuneInString U+0E2A 'ส' starts at 0 found so sua U+0E27 'ว' starts at 3 U+0E31 'ั' starts at 6 U+0E2A 'ส' starts at 9 found so sua U+0E14 'ด' starts at 12 U+0E35 'ี' starts at 15
Structs Go 的结构体是字段的类型集合。它们可用于将数据分组以形成记录。
structs.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 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 package mainimport "fmt" type person struct { name string age int } func newPerson (name string ) *person { p := person{name: name} p.age = 42 return &p } func main () { fmt.Println(person{"Bob" , 20 }) fmt.Println(person{name: "Alice" , age: 30 }) fmt.Println(person{name: "Fred" }) fmt.Println(&person{name: "Ann" , age: 40 }) fmt.Println(newPerson("Jon" )) s := person{name: "Sean" , age: 50 } fmt.Println(s.name) sp := &s fmt.Println(sp.age) sp.age = 51 fmt.Println(sp.age) dog := struct { name string isGood bool }{ "Rex" , true , } fmt.Println(dog) }
log 1 2 3 4 5 6 7 8 9 10 $ go run structs.go {Bob 20} {Alice 30} {Fred 0} &{Ann 40} &{Jon 42} Sean 50 51 {Rex true}
Methods GO支持在结构体类型上定义方法。
methods.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 30 31 package mainimport "fmt" type rect struct { width, height int } func (r *rect) area() int { return r.width * r.height } func (r rect) perim() int { return 2 *r.width + 2 *r.height } func main () { r := rect{width: 10 , height: 5 } fmt.Println("area: " , r.area()) fmt.Println("perim:" , r.perim()) rp := &r fmt.Println("area: " , rp.area()) fmt.Println("perim:" , rp.perim()) }
log 1 2 3 4 5 $ go run methods.go area: 50 perim: 30 area: 50 perim: 30
接下来,我们来看看 Go 用于分组和命名相关方法集的机制:接口。
Interfaces 接口是方法签名的命名集合。
interfaces.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 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 package mainimport ( "fmt" "math" ) type geometry interface { area() float64 perim() float64 } type rect struct { width, height float64 } type circle struct { radius float64 } func (r rect) area() float64 { return r.width * r.height } func (r rect) perim() float64 { return 2 *r.width + 2 *r.height } func (c circle) area() float64 { return math.Pi * c.radius * c.radius } func (c circle) perim() float64 { return 2 * math.Pi * c.radius } func measure (g geometry) { fmt.Println(g) fmt.Println(g.area()) fmt.Println(g.perim()) } func main () { r := rect{width: 3 , height: 4 } c := circle{radius: 5 } measure(r) measure(c) }
log 1 2 3 4 5 6 7 $ go run interfaces.go {3 4} 12 14 {5} 78.53981633974483 31.41592653589793
要了解更多关于Go界面的信息,请查看这篇很棒的博客文章 。
Enums 枚举类型(枚举)是总和类型的一种特例。枚举类型有固定数量的可能值,每个值都有一个不同的名称。Go 并没有将枚举类型作为一种独特的语言特性,但枚举类型很容易使用现有的语言习语来实现。
enums.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 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 package mainimport "fmt" type ServerState int const ( StateIdle = iota StateConnected StateError StateRetrying ) var stateName = map [ServerState]string { StateIdle: "idle" , StateConnected: "connected" , StateError: "error" , StateRetrying: "retrying" , } func (ss ServerState) String() string { return stateName[ss] } func main () { ns := transition(StateIdle) fmt.Println(ns) ns2 := transition(ns) fmt.Println(ns2) } func transition (s ServerState) ServerState { switch s { case StateIdle: return StateConnected case StateConnected, StateRetrying: return StateIdle case StateError: return StateError default : panic (fmt.Errorf("unwknown state: %s" , s)) } return StateConnected }
log 1 2 3 $ go run enums.go connected idle
Struct Embedding Go 支持结构体和接口的嵌入,以表达更无缝的类型组合。这不能与 //go:embed 混淆,后者是 Go 1.16+ 版本中引入的 go 指令,用于将文件和文件夹嵌入应用程序二进制文件。
struct-embedding.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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package mainimport "fmt" type base struct { num int } func (b base) describe() string { return fmt.Sprintf("base with num=%v" , b.num) } type container struct { base str string } func main () { co := container{ base: base{ num: 1 , }, str: "some name" , } fmt.Printf("co={num: %v, str: %v}\n" , co.num, co.str) fmt.Println("also num:" , co.base.num) fmt.Println("describe:" , co.describe()) type describer interface { describe() string } var d describer = co fmt.Println("describer:" , d.describe()) }
log 1 2 3 4 5 $ go run struct-embedding.go co={num: 1, str: some name} also num: 1 describe: base with num=1 describer: base with num=1
参考链接