基础三

本文深入讲解Go语言的基础概念,包括指针的声明和间接引用、结构体的声明和字段访问、数组的声明与赋值、切片的创建及操作。同时,文章提醒读者注意Go中数组和切片的区别,以及在使用slice时的潜在陷阱。
摘要由CSDN通过智能技术生成

说明

  • 本章主要说明Go语言中的复杂结构

  • 下面的示例代码来自于这里

指针

声明

  • 指针保存了变量的内存地址

  • 类型 *T 是指向类型 T 的值的指针。其零值是 nil

var p *int
  • & 符号会生成一个指向其作用对象内存地址的指针
i := 42
p = &i

间接引用

  • * 符号表示指针指向的底层的值,即“间接引用”或“非直接引用”
package main

import "fmt"

func main() {
    i := 10
    p := &i
    fmt.Println(*p) // 通过指针 p 读取 i
    *p = 21         // 通过指针 p 设置 i
    fmt.Println(i)
}
  • Go 没有指针运算

结构体

声明

  • 一个结构体(struct)就是字段的集合,使用typestruct关键字来声明
package main

import "fmt"

type Vertex struct {
    X int
    Y int
}

func main() {
    fmt.Println(Vertex{1, 2})
}

结构体内字段

  • 结构体字段使用点号来访问
package main

import "fmt"

type Vertex struct {
    X int
    Y int
}

func main() {
    v := Vertex{1, 2}
    v.X = 4
    fmt.Println(v.X)
}
  • 结构体内的字段赋值,可参考如下代码:
package main

import "fmt"

type Vertex struct {
    X, Y int
}

var (
    v1 = Vertex{1, 2}  // 类型为 Vertex
    v2 = Vertex{X: 1}  // Y:0 被省略
    v3 = Vertex{}      // X:0 和 Y:0
)

func main() {
    fmt.Println(v1, v2, v3)
}

结构体指针

  • 结构体字段可以通过结构体指针来访问
package main

import "fmt"

type Vertex struct {
    X int
    Y int
}

func main() {
    v := Vertex{1, 2}
    p := &v
    p.X = 1e9// 此处并非是*p.X = 1e9
    fmt.Println(v)
}
  • 特殊的前缀 & 返回一个指向结构体的指针,因此也可以直接这样写:
p  := &Vertex{1, 2} // 类型为 *Vertex

数组

声明

  • 类型 [n]T 是一个有 n 个类型为 T 的值的数组,表达式:
var a [10]int
  • 数组的长度是其类型的一部分,因此数组不能改变大小

赋值

  • 对数组的值操作的代码如下:
package main

import "fmt"

func main() {
    var a [2]string
    a[0] = "Hello"
    a[1] = "World"
    fmt.Println(a[0], a[1])
    fmt.Println(a)
}

切片

声明

  • 一个 slice 会指向一个序列的值,并且包含了长度信息,[]T 是一个元素类型为 T 的切片
package main

import "fmt"

func main() {
    p := []int{2, 3, 5, 7, 11, 13}
    fmt.Println("p ==", p)

    for i := 0; i < len(p); i++ {
        fmt.Printf("p[%d] == %d\n", i, p[i])
    }
}

对slice切片

  • slice 可以重新切片,创建一个新的 slice 值指向相同的数组,表达式:
s[lo:hi]

表示从 lo 到 hi-1 的 slice 元素,含两端,该切片的长度为 hi - lo,因此s[lo:lo] 是空的。而s[lo:lo+1] 有一个元素,下面的代码是一个对slice切片的具体示例

package main

import "fmt"

func main() {
    p := []int{2, 3, 5, 7, 11, 13}
    fmt.Println("p ==", p)
    fmt.Println("p[1:4] ==", p[1:4])

    // 省略下标代表从 0 开始
    fmt.Println("p[:3] ==", p[:3])

    // 省略上标代表到 len(s) 结束
    fmt.Println("p[4:] ==", p[4:])
}

构造 slice

  • slice 由函数 make 创建。这会分配一个零长度的数组并且返回一个 slice
a := make([]int, 5)  // len(a)=5
  • 为了指定容量,可传递第三个参数到 make
b := make([]int, 0, 5) // len(b)=0, cap(b)=5

b = b[:cap(b)] // len(b)=5, cap(b)=5
b = b[1:]      // len(b)=4, cap(b)=4

向 slice 添加元素

  • 向 slice 添加元素是一种常见的操作,因此 Go 提供了一个内建函数 append,表达式为:
func append(s []T, vs ...T) []T

append 的第一个参数 s 是一个类型为 T 的数组&切片,其余类型为 T 的值将会添加到 slice并返回

package main

import "fmt"

func main() {
    var a []int
    printSlice("a", a)

    // append works on nil slices.
    a = append(a, 0)
    printSlice("a", a)

    // the slice grows as needed.
    a = append(a, 1)
    printSlice("a", a)

    // we can add more than one element at a time.
    a = append(a, 2, 3, 4)
    printSlice("a", a)
}

func printSlice(s string, x []int) {
    fmt.Printf("%s len=%d cap=%d %v\n",
        s, len(x), cap(x), x)
}

  • slice与数组的区别是它不声明长度

  • len表示长度,cap表示容量,cap必须大于等于len,以下代码是错误的

a := make([]int,10,3)
  • slice 的零值是 nil,一个 nil 的 slice 的长度和容量是 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值