Go语言入门指南 | 青训营

67 阅读6分钟

Go语言入门指南

目录

变量
匿名变量
常量
判断
循环

函数
切片

Go(又称Golang)是Google的Robert Griesemer,Rob Pike及Ken Thompson开发的一种静态强类型、编译型语言。Go语言语法与C相近,但功能上有:内存安全,GC(垃圾回收),结构形态及CSP-style并发计算。本篇文章将讲述一些基本语法及其特性例子。

变量

先定义一些变量:

var a int 
var b float32
var c,d float64
e,f:=9, 10
var g = "Ricardo"

我们可以看到,在Golang中定义一个变量,需要使用var关键字,而与C或者Java不同的是,我们需要将这个变量的类型写在变量名的后面。不仅如此,在Golang中,允许我们一次性定义多个变量并同时赋值。

还有另外的一种做法,是使用:=这个符号。使用了这个符号之后,开发者不再需要写var关键字,只需要定义变量名,并在后面进行赋值即可。并且,Golang编译器会根据后面的值的类型,自动推导出变量的类型。

在变量的定义过程中,如果定义的时候就赋予了变量的初始值,是不需要再声明变量的类型的,如变量g。

注意,Golang是强类型的一种语言,所有的变量必须拥有类型,并且变量仅仅可以存储特定类型的数据。

匿名变量

标识符为(下划线)的变量,是系统保留的匿名变量,在赋值后,会被立即释放,称之为匿名变量。其作用是变量占位符,对其变量赋值结构。通常会在批量赋值时使用。 例如,函数返回多个值,我们仅仅需要其中部分,则不需要的使用来占位。

func main() {
  // 调用函数,仅仅需要第二个返回值,第一,三使用匿名变量占位
  _, v, _ := getData()
  fmt.Println(v)
}
// 返回两个值的函数
func getData() (int, int, int) {
  // 返回3个值
  return 2, 4, 8
}

如上述代码所示,如果我仅仅需要一个变量的值,就不需要去额外定义一些没有意义的变量名了,仅仅只是需要使用占位符这种“用后即焚”的匿名变量。

常量

在Golang的常量定义中,使用const关键字,并且不能使用:=标识符。

判断

我们在使用Java或者C的时候,写判断语句是这样的:

if(condition){
    ...
}

在Golang中,唯一的不同是不需要小括号,但是大括号还是必须的。如下:

func pow(x, n, lim float64) float64 {
    if v := math.Pow(x, n); v < lim {
        return v
    }
    return lim
}

除去不需要写小括号以外,Golang还允许在判断条件之前执行一个简单的语句,并用一个分号;隔开。

循环

在Golang中,只有一种循环,for循环。

和判断语句一样,在Golang中也是没有小括号的。

func main() {
    sum := 0
    for i := 0; i < 10; i++ {
        sum += i
    }
    fmt.Println(sum)
}

此外,在循环条件中,初始化语句和后置语句是可选的,这个时候把分号去掉,for循环就变成了while循环。

func main() {
    sum := 1
    for sum < 1000 {
        sum += sum
    }
    fmt.Println(sum)
}

不仅如此,如果省略循环条件,该循环就不会结束,因此无限循环可以写得很紧凑,这个时候,和while(true)的效果是一样的。

func main() {
    for {
        ...
    }
}

函数

函数的定义: 在Golang的函数定义中,所有的函数都以func开头,并且Golang命名推荐使用驼峰命名法。

注意,在Golang的函数中,如果首字母是小写,则只能在包内使用;如果首字母是大写,则可以在包外被引入使用。可以理解为,使用小写的函数,是`private`的,使用大写的函数,是`public`的。

在Golang的函数定义中,一样可以不接受参数,或者接受多个参数。而在参数的定义过程中,也是按照定义变量的格式,先定义变量名,再声明变量类型。对于函数的返回类型,也是按照这样的格式,先写函数名,再写返回类型:

func add(x int, y int) int {
    return x + y
}

func main() {
    fmt.Println(add(42, 13))
}

并且,对于相同类型的两个参数,参数类型可以只写一个,用法如下:

func add(x, y int) int {
    return x + y
}

在Golang中,对于函数的返回值,和C以及Java是不一样的。例如下面这个例子:

func swap(x, y string) (string, string) {
    return y, x
}

func main() {
    a, b := swap("hello", "world")
    fmt.Println(a, b)
}

其次,函数的返回值是可以被命名的:

func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return
}

在这里,可以理解为在函数的顶部预先定义了这些变量值,而空的返回语句则默认返回所有已经定义的返回变量。

切片

数组的切片,顾名思义,就是将一个数组按需切出自己所需的部分。

每个数组的大小都是固定的。而切片则为数组元素提供动态大小的、灵活的视角。在实践中,切片比数组更常用。

切片通过两个下标来界定,即一个上界和一个下界,二者以冒号分隔。

a[low : high]

它会选择一个半开区间,包括第一个元素,但排除最后一个元素。

以下表达式创建了一个切片,它包含 a 中下标从 1 到 3 的元素:

a[1:4]

例如:

func main() {
    str := [4]string{
        "aaa",
        "bbb",
        "ccc",
        "ddd",
    }
    fmt.Println(str)

    a := str[0:2]
    b := str[1:3]
    fmt.Println(a, b)

    b[0] = "XXX"
    fmt.Println(a, b)
    fmt.Println(str)
}

我们定义了一个数组,里面含有"aaa","bbb","ccc","ddd"四个元素。然后我们定义了两个切片,a和b,根据定义可以知道,a为"aaa"和"bbb",b为"bbb"和"ccc"。

这个时候,我们把b[0]改成了"XXX",那么b变成了"XXX"和"ccc",这是毋庸置疑的。但是与直觉相违背的是,这个时候的数组str,也变成了"aaa","XXX","ccc","ddd"。

这是因为,Golang中的切片,不是拷贝,而是定义了新的指针,指向了原来数组所在的内存空间。所以,修改了切片数组的值,也就相应的修改了原数组的值了。

此外,切片可以用append增加元素。但是,如果此时底层数组容量不够,此时切片将会指向一个重新分配空间后进行拷贝的数组。

因此可以得出结论:

切片并不存储任何数据,它只是描述了底层数组中的一段。 更改切片的元素会修改其底层数组中对应的元素。 与它共享底层数组的切片都会观测到这些修改。

写在最后

开营的几天在青训营学到了很多 希望后续的学习可以收获更多!!