Go 语言入门指南:基础语法和常用特性解析 | 豆包MarsCode AI刷题

177 阅读7分钟

Golang是一种开源的编程语言,由 Google 的 Robert Griesemer、Rob Pike 和 Ken Thompson 在 2007 年设计并实现。Go 语言以其简洁、高效和并发支持而闻名,它结合了编译语言的性能和解释型语言的开发效率,感觉上是简化版C语言,高效版Python。

1.基本语法

1.1变量

var<变量的声明> a<变量名> int<数据类型>=<值>

值得注意的一点是,go语言中没有字符类型,即比较常见的char,go语言中一般是Unicode编码存储字符,对于abcd等单个的字符,可以使用byte数据类型转为ASCII码进行存储。

自动判断变量类型

a := <值>

const//声明常量

根据上下文自动确定常量类型,即使用const关键字是没有:=这个语法的,你只能用两种类型,如下:

    const s = "constant"    const h = 500000000    const i = 3e20 / h

1.2循环

GO语言中只有一种循环,for循环,基本用法有如下几种

死循环

    for {        fmt.Println("loop")        break    }

基本的条件循环

    for j := 7; j < 9; j++ {        fmt.Println(j)    }

for循环中的三条判断语句可以少任意一条或两条,和Cpp,Python可以使用break和continue来中断循环

1.3选择

没啥好说的,就普通的if,else,但没有括号,且if后面必须直接加{

    if 7%2 == 0 {        fmt.Println("7 is even")    } else {        fmt.Println("7 is odd")    }

这样就不行

    if 7%2 == 0     {        fmt.Println("7 is even")    } 

但是else的{}可以放下来,但不建议

1.4 分支

Switch分支,与C++不同,不需要加break也会自动退出,golang中的Switch接受字符串等字符类型,可以不加Switch的判断条件,直接在每个case里写判断条件代替,if语句,很清楚,Switch开始判断,case结果,不满足default

    switch a {    case 1:        fmt.Println("one")    case 2:        fmt.Println("two")    case 3:        fmt.Println("three")    case 4, 5:        fmt.Println("four or five")    default:        fmt.Println("other")    }    t := time.Now()    switch {    case t.Hour() < 12:        fmt.Println("It's before noon")    default:        fmt.Println("It's after noon")    }

1.5数组

没啥好说的,就数组

func main() {    var a [5]int    a[4] = 100    fmt.Println("get:", a[2])    fmt.Println("len:", len(a))    b := [5]int{1, 2, 3, 4, 5}    fmt.Println(b)    var twoD [2][3]int    for i := 0; i < 2; i++ {        for j := 0; j < 3; j++ {            twoD[i][j] = i + j        }    }    fmt.Println("2d: ", twoD)}

未赋值就输出0,数据用的很少,主要原因是因为长度固定

1.6切片(slice)

没听过,按课的意思,像是vector动态数组

可以在任意时刻更改长度

    s := make([]string, 3)    s[0] = "a"    s[1] = "b"    s[2] = "c"    fmt.Println("get:", s[2])   // c    fmt.Println("len:", len(s)) // 3

关键字看样子是用make来定义,查了一下

make 是一个内置函数,用于创建切片(slice)、映射(map)和通道(channel)类型的实例。它的主要作用是为这些类型分配内存,并对其进行初始化。

make([]T, len, cap)

  • T 是切片元素的类型。
  • len 是切片的长度,即切片当前包含的元素个数。
  • cap 是切片的容量,即切片可以存储的最大元素个数。如果没有指定 cap,则其默认值等于 len

s := make([]string, 3)

那这句代码就是,创建一个字符串切片,长度为3,最大容量为3,但是实际上感觉容量这个参数用处不大,因为到了容量上限,定义的切片会自动扩容

AI对扩容的解释

当你向切片中添加元素时,如果切片的长度还没有达到容量,那么新元素会被添加到切片的末尾,切片的长度会增加。但是,如果切片的长度已经达到了容量,那么再添加新元素时,Go会自动创建一个新的底层数组,其容量是原来的两倍,并将原来的元素复制到新数组中,然后再添加新元素。这个过程称为切片的扩容。

s = append(s, "d")    
s = append(s, "e", "f")
fmt.Println(s) // [a b c d e f]

可以使用append加入元素,有点像Python的list,但因为有扩容这段,需要将append后的数据赋值给原切片,同样可以使用Python的数列切片手段

fmt.Println(s[2:5]) // [c d e] 
fmt.Println(s[:5])  // [a b c d e]  
fmt.Println(s[2:])  // [c d e f]

1.7 map

就字典,感觉和C++一样

创建

    m := make(map[string]int)    m["one"] = 1    m["two"] = 2

删除

    delete(m, "one")

但是有一点注意,它的字典是纯随机的,对于不存在的值返回0

1.8range

有点像enumerate,配合for一起用,不做过多笔记,没啥说的

func main() {    nums := []int{2, 3, 4}    sum := 0    for i, num := range nums {        sum += num        if num == 2 {            fmt.Println("index:", i, "num:", num) // index: 0 num: 2        }    }    fmt.Println(sum) // 9    m := map[string]string{"a": "A", "b": "B"}    for k, v := range m {        fmt.Println(k, v) // b 8; a A    }    for k := range m {        fmt.Println("key", k) // key a; key b    }}

输出

index: 0 num: 2
9
a A
b B
key a
key b

1.9函数

比较特殊的一点,要指明返回值类型

func add2(a, b int) int {    return a + b}

一般都会返回两个值,一个是正确值,一个是错误信息

func exists(m map[string]string, k string) (v string, ok bool) {    v, ok = m[k]    return v, ok}

1.10 指针

定义用*,主要用途,对常用的参数进行修改,因为进入函数的参数是拷贝值,因此需要用指针指向原地址,没记错的话,和C++好像是一样的

func add2(n int) {    n += 2}func add2ptr(n *int) {    *n += 2}func main() {    n := 5    add2(n)    fmt.Println(n) // 5    add2ptr(&n)    fmt.Println(n) // 7}

1.11 结构体

定义一个结构体

type user struct {    name     string    password string}
    a := user{name: "wang", password: "1024"}    b := user{"wang", "1024"}    c := user{name: "wang"}    c.password = "1024"    var d user    d.name = "wang"    d.password = "1024"

它的名字叫user,有两个字段,name和password

剩下的和Python差不多,不写了

1.12 错误

有点像Python里抛出错误的语法,应该是raise ValueError

不写了,就是注意返回的时候多加一个值,没错就正常返回,写一个错误如下

errors.New("not found")

新错误找不到

1.13字符串

有一些操作,在API中可以找到,不再11列举

包括字符串的格式化,Python中的format,很简单就不列举了

1.14json

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它基于JavaScript的一个子集,易于人阅读和编写,同时也易于机器解析和生成。在Go语言中,encoding/json包提供了对JSON数据的编码和解码功能。

JSON操作主要包括以下几个方面:

  1. 编码(Marshal):将Go语言中的数据结构转换为JSON格式的字节序列。这通常用于将数据发送到其他系统或存储到文件中。

  2. 解码(Unmarshal):将JSON格式的字节序列转换为Go语言中的数据结构。这通常用于从其他系统接收数据或从文件中读取数据。

  3. 格式化(MarshalIndent):与编码类似,但会将JSON数据格式化为更易读的形式,通常用于调试或输出到控制台。

  4. 解析(Decode):从输入流(如文件或网络连接)中读取JSON数据并解码到Go语言的数据结构中。

  5. 编码到Writer:将JSON数据编码并直接写入到io.Writer接口的实现中,如os.Filebytes.Buffer

  6. 解码从Reader:从io.Reader接口的实现中读取JSON数据并解码到Go语言的数据结构中

你只需要保证每个结构体中的字段的第一个字母是大写,就可以对这个结构体进行json化

    buf, err := json.Marshal(a)

只看关键代码。返回两个变量,buf是数列化后的结果,这个在上面的那段字里已经说过了

1.15time

看时间,需要注意的只有一点,格式化时间使用一个特定的字符串时间

t.Format("2006-01-02 15:04:05")

字符串里的时间是不能改的,一旦改了,输出的时间就不对

1.16字符串和数字的转换

strconv包,用法很多,但都很简单

n, _ := strconv.ParseInt("11", 10, 64)

三个参数,第一个要转换的数,第二个进制,第三个数据类型

1.17 进程信息 环境变量

os库,可以获取进程运行时的命令行参数

os.Getenv获取环境变量

os.Setenv设置环境变量,

fmt.Println(os.Setenv("AA", "BB"))

这个就是设置AA为BB

exec.Command启动子进程