Go

Go更多类型

Posted by 排球混子 on October 17, 2023

Go更多类型

指针

Go 拥有指针。指针保存了值的内存地址 类型*T是指向T类型值的指针。其零值为nil var p *int

&操作符会生成一个指向其操作数的指针

i := 42
p = &i

*操作符表示指针指向的底层值

fmt.Println(*p)  
*p = 21 
package main  
  
import "fmt"  
  
func main() {  
    i, j := 42, 2701  
    p := &i            // 指向i
    fmt.Println(*p)  
    *p = 21            // 通过指针设置i的值
    fmt.Println(i)  
    p2 := &j           // 指向j
    *p2 = *p2 / 37     // 通过指针进行除法计算
    fmt.Println(j)     // 查看j

这也就是通常所说的“间接引用”或“重定向”。

结构体

一个结构体(struct)就是一组字段(field)

type Vertex struct {
	X int
	Y int
}

结构体字段

结构体字段可以通过点号来访问

func main() {
	v := Vertex{1, 2}
	v.X = 4
	fmt.Println(v.X)
}

结构体指针

结构体字段可以通过结构体指针来访问。 如果我们有一个指向结构体的指针p, 那么可以通过(*p).X来访问X。 但是很啰嗦,所以语言也允许我们使用隐式间接引用, 直接写p.X就可以。

func main() {  
    v := Vertex{1, 2}  
    p := &v  
    p.X = 333  
    fmt.Println(v.X)  
}

结构体文法(Struct Literals)

文法指的是在编程中通过列出结构体中各个字段的值来创建一个新的结构体实例

使用Name:语法可以列出部分字段。 特殊的前缀&可以返回一个指向结构体的指针。

var (  
    v1 = Vertex{1, 2}  
    v2 = Vertex{X: 1}  
    V3 = Vertex{}  
    p = &Vertex{1, 2}  
)

数组

数组[n]T表示有n个T类型的值的数组 表达式var a [10]int声明一个长度为10的int类型的数组 数组的长度是其类型的一部分,因此数组不能改变其大小。这看起来是一个限制,不过没关系,Go提供了Slice

var a [2]string  
a[0] = "Hello"  
a[1] = "World"  
fmt.Println(a)  
primes := [6]int{1, 2, 3, 4, 5, 6}  
fmt.Println(primes)

切片

每个数组的大小都是固定的。而切片则为数组元素提供动态大小的、灵活的视角。在实践中,切片比数组更常用。 类型[]T表示一个元素类型为T的切片 切片通过两个下表来界定, 一个上界一个下界, 二者以冒号分割: a[low:high] 它会选择一个半开区间,它会包含第一个元素,但排除最后一个元素(左闭右开)。

primes := [6]int{1, 2, 3, 4, 5, 6}  
var s []int = primes[1:4]  
fmt.Println(s)

切片就像数组的引用

切片并不存储人物数据,它只是描述了底层数组中的一段。 更改切片的元素会修改其底层数组对应的元素

	names := [4]string{
		"John",
		"Paul",
		"George",
		"Ringo",
	}

	a := names[0:2]     // [John, Paul]
	b := names[1:3]     // [Paul George]

	b[0] = "XXX"        // [John XXX George Ringo]

切片文法

切片文法类似没有长度的数组文法 数组文法[3]int{1,2,3} 下面会创建一个和上面相同的数组,然后构建一个引用了他的切片 []int{1,2,3}

q := []int{2, 3, 5, 7, 9, 11, 13}  
// [2 3 5 7 9 11 13]
r := []bool{true, false, true, true, true}  
// [true false true true true]

s := []struct {  
    i int  
    b bool  
}{  
    {2, true},  
    {3, false},  
    {5, true},  
    {7, true},  
    {9, false},  
    {11, true},  
    {13, true},  
}   // [{2 true} {3 false} {5 true} {7 true} {9 false} {11 true} {13 true}]

切片的长度和容量

切片拥有长度容量。 切片的长度是指切片当前包含的元素数量。 容量切片的容量是指切片底层数组的长度,也就是切片可以容纳的最大元素数量。 长度可以通过len(s)cap(s)获取。

切片的长度通常<=其容量, 因为长度表示实际元素的数量,而容量表示底层数组的大小

slice := make([]int, 5, 10)

上述示例中,slice 是一个切片,其长度为5,容量为10。这意味着它可以容纳5个元素,但最多可以容纳10个元素。切片的长度不能超过容量,否则会导致运行时错误。

nil切片

切片的零值是nil。 nil切片的长度和容量为0且没有底层数组。

package main  
  
import "fmt"  
  
func main() {  
    var s []int  
    fmt.Println(s, len(s), cap(s))  
    if s == nil {  
       fmt.Println("nil")  
    }  
}

用make创建切片

切片可以用内置的make函数来创建,

make函数会分配一个元素为零值的数组并返回一个引用了它的切片 a := make([]int, 5)

要指定容量,make需要第三个参数 a := make([]int, 5, 10)

切片的切片

切片可以容纳任何类型, 甚至是其他的切片

package main  
  
import (  
    "fmt"  
    "strings")  
  
func main() {  
    board := [][]string{  
       []string{"_", "_", "_"},  
       []string{"_", "_", "_"},  
       []string{"_", "_", "_"},  
    }  
    board[0][0] = "X"  
    board[2][2] = "O"  
    board[1][2] = "X"  
    board[1][0] = "O"  
    board[0][2] = "X"  
  
    for i := 0; i < len(board); i++ {  
       fmt.Printf("%s\n", strings.Join(board[i], " "))  
    }  
}

向切片追加元素

Go提供了一个内建append函数。 func append(slice []Type, elems ...Type) []Type 第一个参数slice是一个元素类型为Type的切片, 其余elems会被追加到该切片的末尾 append将返回一个包含原切片所有元素加上新添加元素的切片。 当slice的底层数组太小,不足以容纳所有给定的值时, 它就会分配一个更大的数据。返回的切片会指向这个新分配的数组。

package main  
  
import "fmt"  
  
func printSlice(s []int) {  
    fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)  
}  
  
func main() {  
    var s []int  
    printSlice(s) // len=0 cap=0 []  
    s = append(s, 0)  
    printSlice(s) // len=1 cap=1 [0]  
    s = append(s, 1, 2, 3, 4, 5)  
    printSlice(s)  // len=6 cap=6 [0 1 2 3 4 5]  
}

Range

for循环的range形式可遍历切片或映射。 for循环遍历时,每次迭代都会返回两个值。 第一个值为当前元素的下标, 第二个值为该下标对应元素的副本。

package main  
  
import "fmt"  
  
func main() {  
    var s =  []int{0, 1, 2, 3, 4, 5}  
    for i, v := range s {  
       fmt.Printf("idx is %d %d\n", i, v)  
    }  
}

可以使用_忽略某个值。 for i, _ := range s

映射

映射将key映射到值。 映射的零值为nil。nil映射既没有key, 也不能添加key。 make函数会返回给定类型的映射,并初始化备用。

package main  
  
import "fmt"  
  
type Vertex struct {  
    Lat, Long float64  
}  
  
var m map[string]Vertex  
  
func main() {  
    m = make(map[string]Vertex)  
    m["Bell Labs"] = Vertex{  
       44.123, -99.12,  
    }  
    fmt.Println(m["Bell Labs"])  
}

修改映射

定义映射 m := make(map[T]T) 在映射m中插入或修改元素: m[key] = elem 获取元素 elem = m[key] 删除元素 delete(m, key) 通过双赋值检测某个key是否存在: elem, ok = m[key] 若 key 在 m 中,ok 为 true ;否则,ok 为 false。 若 key 不在映射中,那么 elem 是该映射元素类型的零值。 同样的,当从映射中读取某个不存在的键时,结果是映射的元素类型的零值。  :若 elem 或 ok 还未声明,你可以使用短变量声明: elem, ok := m[key]