Go 学习(一)

使用 := 赋值操作符

在变量初始化时省略变了的类型而有系统自动判断, 而这个时候再在语句上加 var 关键字就显着多余了 因此可以简写为 a:=50, 这是使用变量的首选形式 但是它只能被用在函数体内 而不可以用于全局变量的声明和赋值、

注意

如果在相同的代码中,我们不可以再次对于相同名称的变量使用初始化声明,声明一个局部变量却没有在相同的代码中使用它,同样会得到编译错误,全局变量是允许声明但不使用

在变量声明中, 空白标识符 _ 用于抛弃值, _,b = 5,7 中 5被抛弃

_ 实际上是一个只写变量 你不能得到他的值 这样做是因为 Go语言中你必须使用所有被声明的变量, 但有时并不需要使用从一个函数得到的所有返回值

init 函数

变量除了可以在全局声明中初始化, 也可以在 init 函数中 初始化. 这是一类非常特殊的函数, 它不能够被认为调用,而是在每个包完成初始化后自动执行, 并且执行优先级比 main 函数高。

每个源文件都只能包含一个 init函数,初始化总是以单线程执行, 并且按照包依赖关系顺序执行。

一个可能的用途是在开始执行程序之前对数据进行校验或修复, 以保证程序状态的正确性

格式化说明符

在格式化字符串里, %d 用于格式化整数 (%x%X 用于格式化 16进制表示的数字), %g 用于格式化浮点型(%f输出浮点数, %e 输出科学计数表示法), %0nd 用户规定输出长度为n的整数,其中开头的数字 0 是必须的。

%n.mg 用于表示数字 n 并精确到小数点后 m 位,除了使用 g 之外,还可以使用 e 或者 f,例如:使用格式化字符串 %5.2e 来输出 3.4 的结果为 3.40e+00。

函数

顺序是无关紧要的;鉴于可读性的需求,最好把 main() 函数写在文件的前面,其他函数按照一定逻辑顺序进行编写(例如函数被调用的顺序)。

编写多个函数的主要目的是将一个需要很多行代码的复杂问题分解为一系列简单的任务(那就是函数)来解决。而且,同一个任务(函数)可以被调用多次,有助于代码重用。

Go 里面有三种类型的函数:

  • 普通的带有名字的函数
  • 匿名函数或者lambda函数
  • 方法(Methods)

函数是一等值 (first-class value): 它们可以赋值变量, 就像 add := binOp 一样

这个变量知道自己指向的函数的签名, 所以给它赋一个具有不同签名的函数值是不可能的。

函数值之间可以相互比较: 如果他们引用的是相同的函数或者都是 nil的话, 则认为他们是相同的函数。 函数不能再其他函数里面声明(不能嵌套).可以通过使用匿名函数来破除这个限制。

改变外部变量

传递指针给函数不但可以节省内存(因为没有复制变量的值),而且赋予了函数直接修改外部变量的能力, 所以被修改的变量不再需要使用 return 返回. 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "fmt"

func Multiply(a, b int, reply *int) {
*reply = a * b
}


func main() {
n := 0
//reply := &n
Multiply(10, 5, &n)
fmt.Println("Multiply:", n) // Multiply: 50
}

传递变长参数

如果函数的最后一个参数是采用 …type 的形式,那么这个函数就可以处理一个变长的参数,这个长度可以为 0,这样的函数称为变参函数。

1
2
3

func myFunc(a,b,arg ...int) {}

这个函数接受一个类似某个类型的 slice 的参数.如果变长参数的类型不是都相同的, 则可以使用一下方法来解决:

1、使用结构体:

定义一个结构类型,用来存储所有可能的参数

1
2
3
4
5
6
type Options struct {
par1 type1,
par2 type2,
...
}

可以使用正常的参数 a 和 b,以及一个没有任何初始化的 Options 结构: F1(a, b, Options {})。如果需要对选项进行初始化,则可以使用 F1(a, b, Options {par1:val1, par2:val2})。

2、使用空接口:

如果一个变长参数的类型没有被指定,则可以使用默认的空接口 interface{} 这样就可以接受任何类型的参数.该方案不仅可以用于长度未知的参数, 还可以用于任何不确定类型的参数,一般而言我们会使用一个 for-range 循环以及 switch 结构对每个参数的类型进行判断:

1
2
3
4
5
6
7
8
9
10
11
12
func typecheck(..,..,values … interface{}) {
for _, value := range values {
switch v := value.(type) {
case int: …
case float: …
case string: …
case bool: …
default: …
}
}
}