likes
comments
collection
share

go语法速通

作者站长头像
站长
· 阅读数 16

变量声明

var

在Go语言中,变量可以使用var关键字来声明,例如:

var name string = "John"

这里,我们声明了一个类型为字符串的变量name,并将其初始化为"John"。也可以通过简化声明来利用Go语言的类型推断:

name := "John"

简短声明

这里,我们没有指定name的类型,而是让编译器根据右侧的值推断出它的类型。这被称为简短声明

const

同样,还可以使用const关键字来声明常量。例如:

const pi = 3.14

这里,我们声明了一个名为pi的常量,并将其初始化为3.14。由于常量的值不能更改,因此它们在声明时必须初始化。

分支循环

ifelse

在Go语言中,条件语句if与C或C++非常相似。例如:

if x > 10 {
    fmt.Println("x is greater than 10")
} else {
    fmt.Println("x is less than or equal to 10")
}

这里,我们检查变量x是否大于10。如果是,我们将打印一条消息。否则,我们将打印另一条消息。

注意,必须使用大括号来包装if和else语句块,即使它们只有一条语句。

switch

在Go语言中,switch分支结构非常灵活,可以用于取代多个if-else语句,实现更为清晰的代码逻辑。它的语法格式如下:

switch 变量名 {
case1:
    //执行语句1
case2:
    //执行语句2

default:
    //执行默认语句
}

在switch语句中,可以使用任何类型的变量作为判断条件,而不仅仅是整数或字符类型。每个case后面跟随一个需要匹配的值或表达式,当switch中的变量与某个case后面的值或表达式相等时,会执行该case后的语句。如果没有匹配到任何case,将执行default语句,如果没有default语句,将会自动忽略该switch语句。

和C或C++中的switch语句不同的是,在Go语言中,case后的语句块执行完毕后,不需要显式地使用break语句来跳出switch语句,程序会自动跳出switch语句。这样可以避免C或C++中常见的忘记写break导致程序出错的问题。

除了上述基本用法,Go语言的switch语句还支持一些高级用法,例如可以在switch语句中不带变量名,然后在case后面写上条件表达式,实现更为灵活的条件分支。例如:

switch {
case a < 0:
    fmt.Println("a is negative")
case a == 0:
    fmt.Println("a is zero")
case a > 0:
    fmt.Println("a is positive")
}

此外,Go语言的switch语句还支持多条件匹配,例如:

switch a {
case 0, 1, 2:
    fmt.Println("a is in the range [0, 2]")
case 3, 4, 5:
    fmt.Println("a is in the range [3, 5]")
}

循环

在Go语言中,for循环有几种写法,包括:

  1. 基本的for循环:
for i := 0; i < 10; i++ {
    fmt.Println(i)
}

这里的for循环跟C语言中的循环很类似。for关键字后面紧跟着循环变量的初始化语句,然后是循环条件语句,最后是每次循环后循环变量的更新语句。

  1. 类似while的for循环:
i := 0
for i < 10 {
    fmt.Println(i)
    i++
}

这里的for循环跟while循环类似,只有一个条件语句。当条件为真时,循环会一直执行。

  1. 死循环:
for {
    // 死循环
}

这里的for循环后面什么都没有,表示死循环。一般情况下,这种循环需要在循环体内部使用break或return语句来跳出。

除了上述三种for循环写法,Go语言中还提供了range关键字,可以用来遍历数组、切片、映射、字符串等类型的数据结构。

s := []int{1, 2, 3}
for i, v := range s {
    fmt.Printf("s[%d] = %d\n", i, v)
}

这里的for循环使用了range关键字,可以同时获取数组或切片中的索引和对应的元素值。如果不需要索引,可以用_(下划线)代替。

在for循环中,还可以使用break语句和continue语句来跳出循环或者继续执行下一次循环。

数据类型

数组

在Go语言中,数组是一种值类型的数据结构,可以在声明时初始化,也可以在后续的代码中进行赋值操作。数组的长度是固定的,而且一旦声明后就不能更改,因此数组的使用范围相对有限。

Go语言中的数组可以是一维或者多维的。一维数组是最简单的数组,它包含若干个相同类型的元素,这些元素按照一定的顺序排列,并且每个元素都可以通过一个整数索引来访问。数组的索引从0开始,到长度减1结束。

在Go语言中,可以通过如下的方式来声明一个数组:

var arr [5]int

这个声明语句创建了一个长度为5的整型数组,每个元素的默认值为0。我们也可以在声明时对数组进行初始化,例如:

var arr = [5]int{1, 2, 3, 4, 5}

这个声明语句创建了一个长度为5的整型数组,每个元素的初始值分别为1、2、3、4、5。

当然,我们也可以只对数组的部分元素进行初始化,未初始化的元素将使用默认值。例如:

var arr = [5]int{1, 2, 3}

这个声明语句创建了一个长度为5的整型数组,前三个元素的值为1、2和3,后两个元素的值为0。

在Go语言中,我们可以使用下标来访问数组的元素,例如:

arr[0] = 10
fmt.Println(arr[0])

这个代码片段将数组的第一个元素赋值为10,并且输出数组的第一个元素的值。

在使用数组时,需要注意数组的长度是固定的,因此不能向一个数组中添加或者删除元素。如果需要使用动态大小的数据结构,可以使用切片(Slice)来代替数组。

切片

当我们使用 Go 语言中的切片(slice)时,通常需要掌握以下几个重要的操作:

  1. 创建切片:可以使用 make 函数或直接初始化赋值来创建切片。
// 使用 make 函数创建长度为 3 的切片
s1 := make([]int, 3)

// 直接初始化赋值创建切片
s2 := []int{1, 2, 3}
  1. 访问和修改切片元素:与数组相同,使用索引来访问和修改切片元素。
// 访问切片元素
fmt.Println(s2[0]) // 输出 1

// 修改切片元素
s2[1] = 4
fmt.Println(s2) // 输出 [1 4 3]
  1. 追加元素:使用 append 函数追加元素到切片中,注意需要将追加后的结果重新赋值给原切片变量。
s2 = append(s2, 5)
fmt.Println(s2) // 输出 [1 4 3 5]
  1. 切片复制:使用 copy 函数可以将一个切片复制到另一个切片中,但是要确保目标切片的长度足够容纳源切片的元素。
s3 := make([]int, 3)
copy(s3, s2)
fmt.Println(s3) // 输出 [1 4 3]
  1. 切片长度和容量:切片是一个包含指向底层数组的指针、长度和容量的结构体,可以通过 len 和 cap 函数获取其长度和容量。
fmt.Println(len(s2)) // 输出 4
fmt.Println(cap(s2)) // 输出 4
  1. 切片切割:使用切片切割操作可以获取切片的一个子切片。
s4 := s2[1:3] // 取出索引为 1 到 2 的元素
fmt.Println(s4) // 输出 [4 3]

map

以下是一个示例代码,展示了如何创建、存储、读取和删除 map 中的键值对:

package main

import "fmt"

func main() {
    // 创建一个空 map,键是 string 类型,值是 int 类型
    myMap := make(map[string]int)

    // 向 map 中添加键值对
    myMap["apple"] = 5
    myMap["banana"] = 10
    myMap["orange"] = 15

    // 读取 map 中的键值对
    fmt.Println("Number of apples:", myMap["apple"])
    fmt.Println("Number of bananas:", myMap["banana"])
    fmt.Println("Number of oranges:", myMap["orange"])

    // 修改 map 中的键值对
    myMap["apple"] = 7

    // 删除 map 中的键值对
    delete(myMap, "orange")

    // 遍历 map 中的键值对
    for key, value := range myMap {
        fmt.Printf("Key: %s, Value: %d\n", key, value)
    }
}

输出结果如下:

Number of apples: 5
Number of bananas: 10
Number of oranges: 15
Key: apple, Value: 7
Key: banana, Value: 10

golang的map是完全无序的,遍历的时候不会按照字母顺序,也不会按照插入顺序输出,而是随机顺序。

range

在Go语言中,range关键字可以用来遍历数组、切片、映射(map)、字符串等类型的元素。它会返回两个值,第一个值是当前元素的下标或者键,第二个值是当前元素的值。

下面是使用range遍历一个数组和一个切片的示例代码:

package main

import "fmt"

func main() {
    arr := [5]int{1, 2, 3, 4, 5}
    for index, value := range arr {
        fmt.Printf("arr[%d] = %d\n", index, value)
    }

    slice := []int{6, 7, 8, 9, 10}
    for index, value := range slice {
        fmt.Printf("slice[%d] = %d\n", index, value)
    }
}

输出结果:

arr[0] = 1
arr[1] = 2
arr[2] = 3
arr[3] = 4
arr[4] = 5
slice[0] = 6
slice[1] = 7
slice[2] = 8
slice[3] = 9
slice[4] = 10

如果我们不需要使用下标,可以使用_(下划线)来忽略它:

package main

import "fmt"

func main() {
    slice := []int{6, 7, 8, 9, 10}
    for _, value := range slice {
        fmt.Println(value)
    }
}

输出结果:

6
7
8
9
10

结构体

结构体声明与赋值

结构体是 Golang 中自定义类型的一种,可以理解为带有字段的数据结构,类似于 C/C++ 中的结构体或者 Python 中的类。

每个字段都有一个名称和类型,可以是内置类型、自定义类型或者其他结构体类型。

下面是一个示例代码:

type User struct {
    name     string
    password string
}

func main() {
    user1 := User{"Alice", "123456"}
    fmt.Println(user1)

    user2 := User{
        name: "Bob",
    }
    fmt.Println(user2)

    user3 := &User{
        name:     "Charlie",
        password: "789012",
    }
    fmt.Println(user3)

    user3.password = "654321"
    fmt.Println(user3)
}

在上面的代码中,我们定义了一个名为 User 的结构体,包含了 namepassword 两个字段。我们可以通过结构体类型创建变量,分别用以下几种方式进行初始化:

  1. 直接按字段顺序赋值
    user1 := User{"Alice", "123456"}
    
  2. 指定字段名称和值进行初始化
    user2 := User{
        name: "Bob",
    }
    
  3. 通过指针进行初始化,这里使用了取地址符 &
    user3 := &User{
        name:     "Charlie",
        password: "789012",
    }
    

同时,我们还可以对结构体进行修改,比如对 user3password 字段进行修改。

注意,结构体类型是值类型,因此当我们传递结构体变量作为参数时,会进行值拷贝。如果需要修改原结构体变量,可以使用结构体指针类型。

结构体方法

在 Golang 中,可以为结构体定义方法,方法是一种和结构体绑定的函数,和其他语言的类成员函数有点类似。这样定义的方法可以通过结构体变量来调用。

方法定义的一般形式是:

func (s StructType) methodName(parameters) returnType {
    // method body
}

其中 StructType 是结构体类型的名称,后面紧跟着的是方法名。括号中的 s 是接收器,表示方法是绑定在这个结构体类型上的。接收器可以是结构体类型本身或者结构体类型的指针。

如果接收器是结构体类型本身,则调用时会将接收器的一个副本传递给方法;如果接收器是结构体类型的指针,则调用时会将接收器的指针传递给方法。使用指针作为接收器的主要优势是可以避免结构体类型的拷贝,提高代码的性能。

方法的返回值和普通函数的定义方式一样,可以有一个或多个返回值,也可以没有返回值。当方法有返回值时,使用 return 语句返回结果。

下面是一个示例:

type Rectangle struct {
    width  float64
    height float64
}

// 方法定义
func (r Rectangle) area() float64 {
    return r.width * r.height
}

// 方法定义(使用指针作为接收器)
func (r *Rectangle) scale(factor float64) {
    r.width *= factor
    r.height *= factor
}

func main() {
    rect := Rectangle{width: 10.0, height: 5.0}
    fmt.Println(rect.area()) // 输出:50

    rect.scale(2.0)
    fmt.Println(rect.width, rect.height) // 输出:20 10
}

在上面的示例中,我们定义了一个 Rectangle 结构体类型,然后为其定义了两个方法:area()scale()area() 方法没有使用指针作为接收器,所以调用时会传递一个 Rectangle 值的副本给它。scale() 方法使用指针作为接收器,所以调用时会传递一个 Rectangle 值的指针给它。

main() 函数中,我们创建了一个 Rectangle 类型的变量 rect,调用了 area() 方法并输出了结果。然后调用了 scale() 方法,将 rect 的宽高都乘以了 2,并输出了修改后的结果。

函数与异常处理

函数返回多个值也是 Golang 的一个特色,这种方式可以让代码更加简洁高效。

在 Golang 中,通常将函数的最后一个返回值作为错误信息返回,如果该值为 nil,则表示函数执行成功,否则表示函数执行失败,可以根据这个错误信息进行相应的处理。

下面是一个函数返回多个值的示例:

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("division by zero")
    }
    return a / b, nil
}

在这个例子中,函数 divide 接收两个 int 类型的参数 a 和 b,返回一个 int 类型的商和一个 error 类型的错误信息。

在函数体中,首先判断了除数是否为 0,如果是,则返回一个非空的错误信息;否则,返回两个参数的商和一个 nil 错误信息。

转载自:https://juejin.cn/post/7229277460369227831
评论
请登录