<commit_before>#2.2 Go基础

这小节我们将要介绍如何定义变量、常量、Go内置类型以及一些Go程序设计中的技巧。

##定义变量

Go语言里面定义变量有多种方式。

最基本的定义变量如下，Go变量定义，它的类型是跟在变量后面的，而不是像C一样放前面：

	//定义一个名称为“variableName”，类型为"type"的变量
	var variableName type

定义多个变量

	//定义三个类型都是“type”的三个变量
	var vname1, vname2, vname3 type

定义变量并初始化值

	//初始化“variableName”的变量为“value”值，类型是“type”
	var variableName type = value

同时初始化多个变量

	/*
		定义三个类型都是"type"的三个变量,并且它们分别初始化相应的值
		vname1为v1，vname2为v2，vname3为v3
	*/
	var vname1, vname2, vname3 type= v1, v2, v3

你是不是觉得上面这样的定义有点复杂？没关系，因为Go语言的设计者也发现了，我们来让它变得简单一点。我们可以直接忽略类型声明，那么上面的东西变成这样了：

	/*
		定义三个变量，它们分别初始化相应的值
		vname1为v1，vname2为v2，vname3为v3
		然后Go会根据其相应值的类型来帮你初始化它们
	*/
	var vname1, vname2, vname3 = v1, v2, v3

你还是觉得上面的有些复杂？好吧，我觉得也是。让我们继续简化：

	/*
		定义三个变量，它们分别初始化相应的值
		vname1为v1，vname2为v2，vname3为v3
		编译器会根据初始化的值自动推导出相应的类型
	*/
	vname1, vname2, vname3 := v1, v2, v3

现在是不是看上去非常的简单了？`:=`这个符号直接取代了`var`和`type`，这样的代码是不是很简洁？这种形式叫做简短声明。不过它有一个限制，那就是它只能用在函数内部；在函数外部使用则会无法编译通过，比如说用它来定义全局变量。

`_`（下划线）是个特殊的变量名，任何赋予它的值都会被丢弃。在这个例子中，我们将值`35`赋予`b`，并同时丢弃`34`：

	_, b := 34, 35

Go对于已声明但未使用的变量会在编译阶段报错，比如下面的代码就会产生一个错误：声明了`i`但未使用。

	package main

	func main() {
		var i int
	}

##常量

所谓常量，也就是在编译阶段就确定下来的值，而程序在运行时则无法改变该值。在Go程序中，常量可定义为数值、布尔值或字符串等类型。

它的语法如下：

	const constantName = value

下面是一些常量声明的例子：

	const Pi = 3.1415926
	const i = 10000
	const MaxThread = 10
	const prefix = 'astaxie_'

当然如果需要，也可以明确指定常量的类型：

	const Pi float32 = 3.1415926


##内置基础类型

###Boolean

在Go中，布尔值的类型为`bool`，可用的值是`true`或`false`，默认为`false`。

	//示例代码
	var isActive bool  // 全局变量声明
	var enabled, disabled = true, false  // 忽略类型的声明
	func test() {
		var available bool  // 一般声明
		valid := false      // 简短声明
		available = true    // 赋值操作
	}


###数值类型

整数类型有无符号和带符号两种。Go同时支持`int`和`uint`，这两种类型的长度相同，但具体长度取决于编译器的实现。当前的gc和gccgo编译器在32位和64位平台上都使用32位来表示`int`和`uint`，但未来在64位平台上可能增加到64位。Go里面也有直接定义好位数的类型：`rune`, `int8`, `int16`, `int32`, `int64`和`byte`, `uint8`, `uint16`, `uint32`, `uint64`。`rune`是`int32`的别称，`byte`是`uint8`的别称。

>需要注意的一点是，这些类型的变量之间不允许互相赋值或操作，不然会在编译时引起编译器报错。
>
>如下的代码会产生错误
>
>	var a int8  
>	var b int32  
>	c:=a + b  

浮点数的类型有`float32`和`float64`两种（没有`float`类型），默认是`float64`。

这就是全部吗？No！Go还支持复数。它的默认类型是`complex128`（64位实数+64位虚数）。如果需要小一些的，也有`complex64`(32位实数+32位虚数)。复数的形式为`re + imi`，其中`re`是实数部分，`im`是虚数部分，而最后的`i`是虚数单位。下面是一个使用复数的例子：

	var c complex64 = 5+5i;

	fmt.Printf("Value is: %v", c)

它会打印：(5+5i)

###字符串

我们在上一节中讲过，Go中的字符串都是用`UTF-8`的形式编码的。字符串通过用一对双引号（`""`）或反引号（` `` `）括起来定义，它的类型是`string`。

	//示例代码
	var frenchHello string  // 声明变量为字符串的一般方法
	var emptyString string = ""  // 声明了一个字符串变量，初始化为空字符串
	func test() {
		no, yes, maybe := "no", "yes", "maybe"  // 简短声明，同时声明多个变量
		japaneseHello := "Ohaiou"  // 同上
		frenchHello = "Bonjour"  // 常规赋值
	}

在Go中字符串是不可变的，例如下面的代码编译时会报错：

	var s string = "hello"
	s[0] = 'c'


但如果真的想要修改怎么办呢？下面的代码可以实现：

	s := "hello"
	c := []byte(s)  // 将字符串 s 转换为 []byte 类型
	c[0] = 'c'
	s2 := string(c)  // 再转换回 string 类型
	fmt.Printf("%s\n", s2)


Go中可以使用`+`来链接两个字符串：

	s := "hello,"
	m := " world"
	a := s + m
	fmt.Printf("%s\n", a)

修改字符串也可写为：

	s := "hello"
	s = "c" + s[1:] // 字符串虽不能更改，但可进行切片操作
	fmt.Println("%s\n", s)

如果要声明一个多行的字符串怎么办？可以通过`` ` ``来声明：<commit_msg>Update 2.2.md<commit_after>#2.2 Go基础

这小节我们将要介绍如何定义变量、常量、Go内置类型以及一些Go程序设计中的技巧。

##定义变量

Go语言里面定义变量有多种方式。

最基本的定义变量如下，Go变量定义，它的类型是跟在变量后面的，而不是像C一样放前面：

	//定义一个名称为“variableName”，类型为"type"的变量
	var variableName type

定义多个变量

	//定义三个类型都是“type”的三个变量
	var vname1, vname2, vname3 type

定义变量并初始化值

	//初始化“variableName”的变量为“value”值，类型是“type”
	var variableName type = value

同时初始化多个变量

	/*
		定义三个类型都是"type"的三个变量,并且它们分别初始化相应的值
		vname1为v1，vname2为v2，vname3为v3
	*/
	var vname1, vname2, vname3 type= v1, v2, v3

你是不是觉得上面这样的定义有点复杂？没关系，因为Go语言的设计者也发现了，我们来让它变得简单一点。我们可以直接忽略类型声明，那么上面的东西变成这样了：

	/*
		定义三个变量，它们分别初始化相应的值
		vname1为v1，vname2为v2，vname3为v3
		然后Go会根据其相应值的类型来帮你初始化它们
	*/
	var vname1, vname2, vname3 = v1, v2, v3

你还是觉得上面的有些复杂？好吧，我觉得也是。让我们继续简化：

	/*
		定义三个变量，它们分别初始化相应的值
		vname1为v1，vname2为v2，vname3为v3
		编译器会根据初始化的值自动推导出相应的类型
	*/
	vname1, vname2, vname3 := v1, v2, v3

现在是不是看上去非常的简单了？`:=`这个符号直接取代了`var`和`type`，这样的代码是不是很简洁？这种形式叫做简短声明。不过它有一个限制，那就是它只能用在函数内部；在函数外部使用则会无法编译通过，比如说用它来定义全局变量。

`_`（下划线）是个特殊的变量名，任何赋予它的值都会被丢弃。在这个例子中，我们将值`35`赋予`b`，并同时丢弃`34`：

	_, b := 34, 35

Go对于已声明但未使用的变量会在编译阶段报错，比如下面的代码就会产生一个错误：声明了`i`但未使用。

	package main

	func main() {
		var i int
	}

##常量

所谓常量，也就是在编译阶段就确定下来的值，而程序在运行时则无法改变该值。在Go程序中，常量可定义为数值、布尔值或字符串等类型。

它的语法如下：

	const constantName = value

下面是一些常量声明的例子：

	const Pi = 3.1415926
	const i = 10000
	const MaxThread = 10
	const prefix = 'astaxie_'

当然如果需要，也可以明确指定常量的类型：

	const Pi float32 = 3.1415926


##内置基础类型

###Boolean

在Go中，布尔值的类型为`bool`，可用的值是`true`或`false`，默认为`false`。

	//示例代码
	var isActive bool  // 全局变量声明
	var enabled, disabled = true, false  // 忽略类型的声明
	func test() {
		var available bool  // 一般声明
		valid := false      // 简短声明
		available = true    // 赋值操作
	}


###数值类型

整数类型有无符号和带符号两种。Go同时支持`int`和`uint`，这两种类型的长度相同，但具体长度取决于编译器的实现。当前的gc和gccgo编译器在32位和64位平台上都使用32位来表示`int`和`uint`，但未来在64位平台上可能增加到64位。Go里面也有直接定义好位数的类型：`rune`, `int8`, `int16`, `int32`, `int64`和`byte`, `uint8`, `uint16`, `uint32`, `uint64`。`rune`是`int32`的别称，`byte`是`uint8`的别称。

>需要注意的一点是，这些类型的变量之间不允许互相赋值或操作，不然会在编译时引起编译器报错。
>
>如下的代码会产生错误
>
>	var a int8  
>	var b int32  
>	c:=a + b  

浮点数的类型有`float32`和`float64`两种（没有`float`类型），默认是`float64`。

这就是全部吗？No！Go还支持复数。它的默认类型是`complex128`（64位实数+64位虚数）。如果需要小一些的，也有`complex64`(32位实数+32位虚数)。复数的形式为`re + imi`，其中`re`是实数部分，`im`是虚数部分，而最后的`i`是虚数单位。下面是一个使用复数的例子：

	var c complex64 = 5+5i;

	fmt.Printf("Value is: %v", c)

它会打印：(5+5i)

###字符串

我们在上一节中讲过，Go中的字符串都是用`UTF-8`的形式编码的。字符串通过用一对双引号（`""`）或反引号（` `` `）括起来定义，它的类型是`string`。

	//示例代码
	var frenchHello string  // 声明变量为字符串的一般方法
	var emptyString string = ""  // 声明了一个字符串变量，初始化为空字符串
	func test() {
		no, yes, maybe := "no", "yes", "maybe"  // 简短声明，同时声明多个变量
		japaneseHello := "Ohaiou"  // 同上
		frenchHello = "Bonjour"  // 常规赋值
	}

在Go中字符串是不可变的，例如下面的代码编译时会报错：

	var s string = "hello"
	s[0] = 'c'


但如果真的想要修改怎么办呢？下面的代码可以实现：

	s := "hello"
	c := []byte(s)  // 将字符串 s 转换为 []byte 类型
	c[0] = 'c'
	s2 := string(c)  // 再转换回 string 类型
	fmt.Printf("%s\n", s2)


Go中可以使用`+`来链接两个字符串：

	s := "hello,"
	m := " world"
	a := s + m
	fmt.Printf("%s\n", a)

修改字符串也可写为：

	s := "hello"
	s = "c" + s[1:] // 字符串虽不能更改，但可进行切片操作
	fmt.Printf("%s\n", s)

如果要声明一个多行的字符串怎么办？可以通过`` ` ``来声明：
{'fraction_non_alphanumeric': 0.15428845232390992, 'fraction_numerical': 0.04344353937070756, 'mean_word_length': 5.163385826771654, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1380602', 'n_tokens_mistral': 4556, 'n_tokens_neox': 4817, 'n_words': 448}