Go 的 Hello World 实践
Go的运行环境安装参考 Install Go
使用任意文本编辑器或者IDE编写代码如下,文件名为 hello-world.go :
package main
import ("fmt")
func main() {
fmt.Println("Hello World!")
}
使用 go run <程序文件> 运行 go 程序:
$ go run hello-world.go
hello world
使用 go build <程序文件> 编译 go 程序为二进制文件:
$ go build hello-world.go
$ ls
hello-world hello-world.go
执行编译的生成的二进制文件 hello-world ,效果和go run 一样:
$ ./hello-world
hello world
Go 语法
Go文件由以下部分组成:
- 包声明(Package declaration)
- 导入包(Import packages)
- 函数(Functions)
- 语句和表达式(Statements and expressions)
看看如下示例代码,以便更好的理解:
package main
import ("fmt")
func main() {
fmt.Println("Hello World!")
}
示例说明:
- 第一行:在Go语言里,所有的程序都是包的一部分。这里使用 package 关键字定义这个程序属于哪个包。这里定义程序归属 main 包;
- 第二行:import ("fmt") 导入 fmt 包中的所有文件;
- 第三行:一行空行,Go语言会忽略空白,使用空白内容增加程序的可读性;
- 第四行:func main() {} 是一个函数。其花括号{}内的任何代码都将被执行。
- 第五行:fmt.Println() 是fmt包中提供的一个函数,它用于输出/打印文本。在这个示例中,它将输出“Hello World!”。
Note: In Go, any executable code belongs to the main package.
Go 语句
fmt.Println("Hello World!")
是一个语句。
在 Go 语言中,语句以行结尾(按Enter键)或分号“;”分隔。
按Enter键会隐式地将“;”添加到行的末尾(不会显示在源代码中)。
左花括号{不能出现在一行的开头。
比如执行如下代码,会报错 missing function body
和 syntax error: unexpected semicolon or newline before {
package main
import ("fmt")
func main()
// { 在行开头会报错
{
fmt.Println("Hello World!")
}
Go 代码压缩
Go 语言允许编写更紧凑的代码,如下所示(但不推荐,会让代码难以阅读):
package main; import ("fmt"); func main() { fmt.Println("Hello World!");}
Go 注释
注释是在执行时被忽略的文本。注释可以用来解释代码,并使其更具可读性。在测试替代代码时,注释也可以用于阻止代码执行。Go支持单行或多行注释。
单行注释
单行注释以两个正斜杠(//
)开头,编译器将忽略//
和行尾之间的任何文本(不会执行)。
// This is a comment
package main
import ("fmt")
func main() {
// This is a comment
fmt.Println("Hello World!") // This is a comment
// fmt.Println("This line does not execute")
}
多行注释
多行注释以/*
开头,以*/
结尾。编译器将忽略/和/之间的任何文本:
package main
import ("fmt")
func main() {
/* The code below will print Hello World
to the screen, and it is amazing */
fmt.Println("Hello World!")
}
Go 变量
变量是用于存储数据值的容器。
Go 的变量类型
在 Go 语言中,有多种变量类型,比如:
- int - 存储整数,比如 123 或 -123
- float32 - 存储带小数的浮点数,比如 19.99 或 -19.99
- string - 存储文本,比如 “Hello World”。字符串值需用双引号括起来
- bool - 存储两个状态值, true 或者 false
更多变量类型在数据类型章节深入说明。
变量命名规则
变量可以有一个简短的名称(如x和y)或一个更具描述性的名称(年龄、价格、carname等)。
Go变量命名规则:
- 变量名必须以字母或下划线字符(_)开头
- 变量名不能以数字开头
- 变量名只能包含字母数字字符和下划线(
A-z、A-z
、0-9
和_
) - 变量名称区分大小写(age、Age和AGE是三个不同的变量)
- 变量名的长度没有限制
- 变量名不能包含空格
- 变量名不能是任何Go关键字
多单词变量名
包含多个单词的变量名比较难阅读。
有几种方法用来提高它们的可读性:
驼峰命名法
除第一个单词外,每个单词都以大写字母开头:
myVariableName = "John"
帕斯卡命名法
每个单词都以一个大写字母开头:
MyVariableName = "John"
蛇式命名法
每个单词由一个下划线字符分隔:
my_variable_name = "John"
声明(创建)变量
有两种方式声明变量
- 一种是使用 var 关键字,其后跟变量名称和类型,语法如下:
var variablename type = value
注意: type 和 value 至少需指定一个
- 另一种是使用 := 标识符,其后跟变量值,语法如下:
variablename := value
这种声明方式下,变量的类型是根据值推断的,由编译器根据值觉得变量类型。
使用这种声明方式,变量的值是必须指定的。
带初始值的变量声明
如果变量的值从一开始就已知,则可以声明该变量并在一行中为其赋值:
package main
import ("fmt")
func main() {
var student1 string = "John" //type is string
var student2 = "Jane" //type is inferred
x := 2 //type is inferred
fmt.Println(student1)
fmt.Println(student2)
fmt.Println(x)
}
不带初始值的变量声明
在Go中,所有变量都需要被初始化。因此,如果您声明一个没有初始值的变量,其值将设置为其类型的默认值:
package main
import ("fmt")
func main() {
var a string // 默认 ""
var b int // 默认 0
var c bool // 默认 false
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
在声明后赋值
可以在变量声明后将值赋给该变量。这对于值最初未知的情况下是有帮助的。
package main
import ("fmt")
func main() {
var student1 string
student1 = "John"
fmt.Println(student1)
}
var 和 := 的区别
var | := |
---|---|
可以在函数外部和内部使用 | 只能在函数内部使用 |
变量的声明和赋值可以分开 | 变量的声明和赋值不可以分开(需要在一行) |
多个变量声明
在Go中,允许在同一行中声明多个变量。
package main
import ("fmt")
func main() {
var a, b, c, d int = 1, 3, 5, 7
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(d)
}
注意:如果使用type关键字,则每行只能声明一种类型的变量。
如果未指定type关键字,则可以在同一行中声明不同类型的变量:
package main
import ("fmt")
func main() {
var a, b = 6, "Hello"
c, d := 7, "World!"
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(d)
}
在块中声明变量
为了提高可读性,还可以将多个变量声明分组到一个块中:
package main
import ("fmt")
func main() {
var (
a int
b int = 1
c string = "hello"
)
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
如果一个变量应该具备一个无法更改的固定值,那么可以使用 const
关键字。
const
关键字将变量声明为“常数”,表明这个变量是只读的,不可更改的。
语法如下:
const CONSTNAME type = value
很显然,常量的声明中,赋值是必须的。
常量声明
以下是在Go中声明常量的示例:
package main
import ("fmt")
const PI = 3.14
func main() {
fmt.Println(PI)
}
常量规则
- 常量名称遵循与变量相同的命名规则
- 常量名称通常用大写字母书写(便于识别和区分变量)
- 常量可以在函数内部和外部声明
常量类型
有两种类型的常量:
- 类型常量(Typed constants)
- 无类型常量(Untyped constants)
类型常量(Typed constants)
声明常量时指定类型,常量即为类型常量,类型常量的类型就是指定的类型:
package main
import ("fmt")
const A int = 1
func main() {
fmt.Println(A)
}
无类型常量(Untyped constants)
声明常量时不指定类型,常量即为无类型常量,无类型常量的类型由编译器通过其值推断:
package main
import ("fmt")
const A = 1
func main() {
fmt.Println(A)
}
常量的只读性和不可更改性
声明一个常量后,将不能更改其值,否则会报错:
package main
import ("fmt")
func main() {
const A = 1
A = 2
fmt.Println(A)
}
// 报错:./prog.go:8:7: cannot assign to A
多个常量声明
为了便于阅读,可以将多个常量分组为一个块进行声明:
package main
import ("fmt")
const (
A int = 1
B = 3.14
C = "Hi!"
)
func main() {
fmt.Println(A)
fmt.Println(B)
fmt.Println(C)
}
Go 输出函数
Go 语言中有三个函数用于输出文本:
- Print()
- Println()
- Printf()
Print() 函数
Print() 函数使用默认格式打印参数。
package main
import ("fmt")
func main() {
var i,j string = "Hello","World"
fmt.Print(i)
fmt.Print(j)
}
// Result:
// HelloWorld
如果我们想在新行中打印参数,我们需要使用\n
。
package main
import ("fmt")
func main() {
var i,j string = "Hello","World"
fmt.Print(i, "\n")
fmt.Print(j, "\n")
}
// Result:
// Hello
// World
也可以只使用一个Print()来打印多个变量。
package main
import ("fmt")
func main() {
var i,j string = "Hello","World"
fmt.Print(i, "\n",j)
}
// Result:
// Hello
// World
如果两个参数都不是字符串,则Print()在它们之间插入一个空格:
package main
import ("fmt")
func main() {
var i,j = 10,20
fmt.Print(i,j)
}
// Result:
// 10 20
Println() 函数
Println() 函数与 Print() 类似,不同之处在于在参数之间添加了一个空格,并在末尾添加了一行换行符:
package main
import ("fmt")
func main() {
var i,j string = "Hello","World"
fmt.Println(i,j)
}
// Result:
// Hello World
Printf() 函数
函数的 Printf() 首先根据给定的格式化谓词格式化参数,然后打印它们。
这里我们将使用两个格式化动词:
%v
用于打印参数的值%T
用于打印参数的类型
package main
import ("fmt")
func main() {
var i string = "Hello"
var j int = 15
fmt.Printf("i has value: %v and type: %T\n", i, i)
fmt.Printf("j has value: %v and type: %T", j, j)
}
// Result:
// i has value: Hello and type: string
// j has value: 15 and type: int
格式化谓词 (formatting verbs)
Go 提供了几个可与 Printf() 函数一起使用的格式化谓词。
通用格式化谓词
如下格式化谓词适用于所有的数据类型:
Verb | Description |
---|---|
%v | 以默认格式打印值 |
%#v | 以 Go 语法格式打印值 |
%T | 打印值的类型 |
%% | 打印 % 符号 |
示例如下:
package main
import ("fmt")
func main() {
var i = 15.5
var txt = "Hello World!"
fmt.Printf("%v\n", i)
fmt.Printf("%#v\n", i)
fmt.Printf("%v%%\n", i)
fmt.Printf("%T\n", i)
fmt.Printf("%v\n", txt)
fmt.Printf("%#v\n", txt)
fmt.Printf("%T\n", txt)
}
/*
Result:
15.5
15.5
15.5%
float64
Hello World!
"Hello World!"
string
*/
整数格式化谓词
以下谓词可以与整数数据类型一起使用:
Verb | Description |
---|---|
%b | 二进制输 |
%d | 十进制输出 |
%+d | 十进制输出且总是显示符号 |
%o | 八进制 |
%O | 以0o开头显示的八进制 |
%x | 十六进制, 小写字母显示 |
%X | 十六进制, 大写字母显示 |
%#x | 以0x开头显示的十六进制 |
%4d | 填充空格(宽度4,右对齐) |
%-4d | 填充空格(宽度4,左对齐) |
%04d | 填充零(宽度4) |
示例如下:
package main
import ("fmt")
func main() {
var i = 15
fmt.Printf("%b\n", i)
fmt.Printf("%d\n", i)
fmt.Printf("%+d\n", i)
fmt.Printf("%o\n", i)
fmt.Printf("%O\n", i)
fmt.Printf("%x\n", i)
fmt.Printf("%X\n", i)
fmt.Printf("%#x\n", i)
fmt.Printf("%4d\n", i)
fmt.Printf("%-4d\n", i)
fmt.Printf("%04d\n", i)
}
/*
Result:
1111
15
+15
17
0o17
f
F
0xf
15
15
0015
*/
字符串格式化谓词
以下谓词可以与字符串数据类型一起使用:
Verb | Description |
---|---|
%s | 将值打印为纯字符串 |
%q | 将值打印为双引号括住的字符串 |
%8s | 将值打印为纯字符串(宽度8,右对齐) |
%-8s | 将值打印为纯字符串(宽度8,左对齐) |
%x | 将值打印为byte值的十六进制转储 |
% x | 将值打印为带空格的十六进制转储 |
示例如下:
package main
import ("fmt")
func main() {
var txt = "Hello"
fmt.Printf("%s\n", txt)
fmt.Printf("%q\n", txt)
fmt.Printf("%8s\n", txt)
fmt.Printf("%-8s\n", txt)
fmt.Printf("%x\n", txt)
fmt.Printf("% x\n", txt)
}
/*
Result:
Hello
"Hello"
Hello
Hello
48656c6c6f
48 65 6c 6c 6f
*/
布尔格式化谓词
以下谓词可以与布尔数据类型一起使用:
Verb | Description |
---|---|
%t | 布尔运算符的值,格式为 true 或 false(与 %v 相同) |
示例如下:
package main
import ("fmt")
func main() {
var i = true
var j = false
fmt.Printf("%t\n", i)
fmt.Printf("%t\n", j)
}
/*
Result:
true
false
*/
浮点值格式化谓词
以下谓词可以与浮点数据类型一起使用:
Verb | Description |
---|---|
%e | 以“e”为指数的科学记数法 |
%f | 小数形式,无指数 |
%.2f | 默认宽度,精度2 |
%6.2f | 宽度6,精度2 |
%g | 根据需要使用指数,仅使用必要的数字 |
示例如下:
package main
import ("fmt")
func main() {
var i = 3.141
fmt.Printf("%e\n", i)
fmt.Printf("%f\n", i)
fmt.Printf("%.2f\n", i)
fmt.Printf("%6.2f\n", i)
fmt.Printf("%g\n", i)
}
/*
Result:
3.141000e+00
3.141000
3.14
3.14
3.141
*/
GO 基本数据类型
数据类型是编程中的一个重要概念。数据类型指定变量值的大小和类型。
Go是静态类型的,这意味着一旦定义了变量类型,它就只能存储该类型的数据。
Go有三种基本数据类型:
- bool: 表示布尔值,为 true 或 false
- Numeric: 表示整数类型、浮点值和复数
- string: 表示字符串值
布尔
布尔数据类型是用 bool
关键字声明的,并且只能取 true 或 false值。
布尔数据类型的默认值为 false。
此示例显示了声明布尔变量的一些不同方法:
package main
import ("fmt")
func main() {
var b1 bool = true // typed declaration with initial value
var b2 = true // untyped declaration with initial value
var b3 bool // typed declaration without initial value
b4 := true // untyped declaration with initial value
fmt.Println(b1) // Returns true
fmt.Println(b2) // Returns true
fmt.Println(b3) // Returns false
fmt.Println(b4) // Returns true
}
整数
整数数据类型用于存储整数,如35、-50或1345000。
整数数据类型有两类:
- 有符号整数 - 可以存储正值和负值
- 无符号整数 - 只能存储非负值
Tip: 整数的默认类型为 int
. 如果不指定类型, 默认类型会是 int
。
有符号整数
用 int
关键字声明有符号整数,可以存储正值和负值:
package main
import ("fmt")
func main() {
var x int = 500
var y int = -4500
fmt.Printf("Type: %T, value: %v", x, x)
fmt.Printf("Type: %T, value: %v", y, y)
}
Go 有五个关键字 / 有符号整数类型:
Type | Size | Range |
---|---|---|
int | Depends on platform: 32 bits in 32 bit systems and 64 bit in 64 bit systems | -2147483648 to 2147483647 in 32 bit systems and -9223372036854775808 to 9223372036854775807 in 64 bit systems |
int8 | 8 bits/1 byte | -128 to 127 |
int16 | 16 bits/2 byte | -32768 to 32767 |
int32 | 32 bits/4 byte | -2147483648 to 2147483647 |
int64 | 64 bits/8 byte | -9223372036854775808 to 9223372036854775807 |
无符号整数
用 uint
关键字声明有符号整数,只可以存储非负值:
package main
import ("fmt")
func main() {
var x uint = 500
var y uint = 4500
fmt.Printf("Type: %T, value: %v", x, x)
fmt.Printf("Type: %T, value: %v", y, y)
}
Go- 有五个关键字 / 无符号整数类型:
Type | Size | Range |
---|---|---|
uint | Depends on platform: 32 bits in 32 bit systems and 64 bit in 64 bit systems | 0 to 4294967295 in 32 bit systems and 0 to 18446744073709551615 in 64 bit systems |
uint8 | 8 bits/1 byte | 0 to 255 |
uint16 | 16 bits/2 byte | 0 to 65535 |
uint32 | 32 bits/4 byte | 0 to 4294967295 |
uint64 | 64 bits/8 byte | 0 to 18446744073709551615 |
使用哪种整数类型?
要选择的整数类型取决于变量必须存储的值。
此示例将导致一个错误,因为 1000 超出了 int8 的范围(从-128到127):
package main
import ("fmt")
func main() {
var x int8 = 1000
fmt.Printf("Type: %T, value: %v", x, x)
}
// Result:
// ./prog.go:5:7: constant 1000 overflows int8
浮点数
浮点数据类型用于存储带小数点的正数和负数,如35.3、-2.34或3597.34987。
浮点数据类型有两个关键字,对应两种数据精度:
Type | Size | Range |
---|---|---|
float32 | 32 bits | -3.4e+38 to 3.4e+38. |
float64 | 64 bits | -1.7e+308 to +1.7e+308. |
float32
此示例说明如何声明float32类型的一些变量:
package main
import ("fmt")
func main() {
var x float32 = 123.78
var y float32 = 3.4e+38
fmt.Printf("Type: %T, value: %v\n", x, x)
fmt.Printf("Type: %T, value: %v", y, y)
}
float64
float64数据类型可以存储比float32更大的一组数字。
此示例说明如何声明float64类型的变量:
package main
import ("fmt")
func main() {
var x float64 = 1.7e+308
fmt.Printf("Type: %T, value: %v", x, x)
}
字符串
字符串数据类型用于存储一系列字符(文本)。字符串值必须用双引号括起来:
package main
import ("fmt")
func main() {
var txt1 string = "Hello!"
var txt2 string
txt3 := "World 1"
fmt.Printf("Type: %T, value: %v\n", txt1, txt1)
fmt.Printf("Type: %T, value: %v\n", txt2, txt2)
fmt.Printf("Type: %T, value: %v\n", txt3, txt3)
}
/*
Result:
Type: string, value: Hello!
Type: string, value:
Type: string, value: World 1
*/
Go 数组
数组用于将同一类型的多个值存储在一个变量中,而不是为每个值声明单独的变量。
数组声明
在 Go 语言中,有两种方式声明数组:
1. 使用 var
关键字:
语法
var array_name = [length]datatype{values} // here length is defined
或者
var array_name = [...]datatype{values} // here length is inferred
Note: 不指定长度时, [...]
是必须的
2. 使用 :=
符号:
语法
array_name := [length]datatype{values} // here length is defined
或者
array_name := [...]datatype{values} // here length is inferred
Note: 不指定长度时, [...]
是必须的
length 指定可存储在数组中的元素数量。Go 语言中数组的长度是固定的。数组的长度要么是由定义时指定,要么是由初始赋值时编译器推断(未指定长度时,编译器根据赋值数量推断数组长度).
数组示例
此示例声明了两个指定了长度的数组(arr1和arr2):
package main
import ("fmt")
func main() {
var arr1 = [3]int{1,2,3}
arr2 := [5]int{4,5,6,7,8}
fmt.Println(arr1)
fmt.Println(arr2)
}
/*
Result:
[1 2 3]
[4 5 6 7 8]
*/
此示例声明了两个具有推断长度的数组(arr1和arr2):
package main
import ("fmt")
func main() {
var arr1 = [...]int{1,2,3}
arr2 := [...]int{4,5,6,7,8}
fmt.Println(arr1)
fmt.Println(arr2)
}
/*
Result:
[1 2 3]
[4 5 6 7 8]
*/
此示例声明一个字符串数组:
package main
import ("fmt")
func main() {
var cars = [4]string{"Volvo", "BMW", "Ford", "Mazda"}
fmt.Print(cars)
}
/*
Result:
[Volvo BMW Ford Mazda]
*/
访问数组的元素
可以通过索引号来访问特定的数组元素。在 Go 中,数组索引从 0 开始。即 [0] 是第一个元素,[1] 是第二个元素,依次类推。
此示例说明如何访问 prices 数组中的第一个和第三个元素:
package main
import ("fmt")
func main() {
prices := [3]int{10,20,30}
fmt.Println(prices[0])
fmt.Println(prices[2])
}
/*
Result:
10
30
*/
修改数组的元素
和数组访问一样,可以通过索引号来更改特定数组元素的值。
此示例说明如何更改 prices 数组中第三个元素的值:
package main
import ("fmt")
func main() {
prices := [3]int{10,20,30}
prices[2] = 50
fmt.Println(prices)
}
/*
Result:
[10 20 50]
*/
数组初始化
默认值
如果一个数组或它其中的某个元素在代码中尚未初始化,则会为它分配其对应类型的默认值。
如下示例:
package main
import ("fmt")
func main() {
arr1 := [5]int{} //not initialized
arr2 := [5]int{1,2} //partially initialized
arr3 := [5]int{1,2,3,4,5} //fully initialized
fmt.Println(arr1)
fmt.Println(arr2)
fmt.Println(arr3)
}
/*
Result:
[0 0 0 0 0]
[1 2 0 0 0]
[1 2 3 4 5]
*/
仅初始化特定元素
可以只初始化数组中的特定元素。
此示例仅初始化数组的第二个和第三个元素:
package main
import ("fmt")
func main() {
arr1 := [5]int{1:10,2:40}
fmt.Println(arr1)
}
/*
Result:
[0 10 40 0 0]
*/
示例说明
上面的数组有5个元素。
- 1:10 表示:将10分配给数组索引1(第二个元素)。
- 2:40 表示:将40分配给数组索引2(第三个元素)。
数组长度获取
len() 函数用于获取数组的长度:
package main
import ("fmt")
func main() {
arr1 := [4]string{"Volvo", "BMW", "Ford", "Mazda"}
arr2 := [...]int{1,2,3,4,5,6}
fmt.Println(len(arr1))
fmt.Println(len(arr2))
}
/*
Result:
4
6
*/
Go 切片
创建切片
切片与数组相似,但更强大、更灵活。
与数组一样,切片也用于在单个变量中存储相同类型的多个值。
然而,与数组不同的是,切片的长度可以根据需要增长或收缩。
在Go中,有几种方法可以创建切片:
- 使用
[]datatype{values}
格式 - 从数组创建切片
- 使用 make() 函数
使用 []datatype{values}
格式创建切片
语法
slice_name := []datatype{values}
声明切片的常见方法如下:
myslice := []int{}
上面的代码声明了一个长度为0、容量为0的空切片。
要在声明时初始化切片,可以使用以下方法:
myslice := []int{1,2,3}
上面的代码声明了一个长度为3、容量为3的整数切片。
Go 语言中,有两种函数分别用来获取切片的长度和容量:
- len() 函数:返回切片的长度(切片中的元素数量)
- cap() 函数:返回切片的容量(切片可以增大到或缩小到的元素数)
示例
如下示例展示了如何使用[]datatype{values}
格式创建切片并使用上述函数获取其长度和容量:
package main
import ("fmt")
func main() {
myslice1 := []int{}
fmt.Println(len(myslice1))
fmt.Println(cap(myslice1))
fmt.Println(myslice1)
myslice2 := []string{"Go", "Slices", "Are", "Powerful"}
fmt.Println(len(myslice2))
fmt.Println(cap(myslice2))
fmt.Println(myslice2)
}
/*
0
0
[]
4
4
[Go Slices Are Powerful]
*/
在上面的例子中,可以看到在第一个切片(myslice1)中,没有指定实际元素,因此切片的长度和容量都将为零。在第二个切片(myslice2)中,指定了元素,并且长度和容量都等于指定的实际元素的数量。
从数组创建切片
也可以通过对数组进行切片来创建切片:
语法
var myarray = [length]datatype{values} // An array
myslice := myarray[start:end] // A slice made from the array
示例
使用示例说明如何从数组创建切片:
package main
import ("fmt")
func main() {
arr1 := [6]int{10, 11, 12, 13, 14,15}
myslice := arr1[2:4]
fmt.Printf("myslice = %v\n", myslice)
fmt.Printf("length = %d\n", len(myslice))
fmt.Printf("capacity = %d\n", cap(myslice))
}
/*
myslice = [12 13]
length = 2
capacity = 4
*/
在上面的例子中,myslice
是一个长度为 2 的切片。它由arr1组成,arr1
是一个长度为6的数组。
切片数组的第三个元素开始(值为 12 的元素,数组索引从 0 开始), 切片可以增长到数组的末尾。这意味着切片的容量为 4。
如果 myslice
从索引 0 开始,则切片容量将为 6。
使用 make() 函数创建切片
可以使用 make() 函数创建切片。
语法
slice_name := make([]type, length, capacity)
Note: 如果不指定 capacity 参数,它将等于 length。
示例
以下示例说明了如何使用 make() 函数创建切片:
package main
import ("fmt")
func main() {
myslice1 := make([]int, 5, 10)
fmt.Printf("myslice1 = %v\n", myslice1)
fmt.Printf("length = %d\n", len(myslice1))
fmt.Printf("capacity = %d\n", cap(myslice1))
// with omitted capacity
myslice2 := make([]int, 5)
fmt.Printf("myslice2 = %v\n", myslice2)
fmt.Printf("length = %d\n", len(myslice2))
fmt.Printf("capacity = %d\n", cap(myslice2))
}
/*
myslice1 = [0 0 0 0 0]
length = 5
capacity = 10
myslice2 = [0 0 0 0 0]
length = 5
capacity = 5
*/
访问切片元素
和数组一样,通过索引号访问特定的切片元素,索引从 0 开始,[0] 表明访问第一个元素,[1] 表明访问第二个元素,以此类推。
访问切片的第一个和第三个元素的示例如下:
package main
import ("fmt")
func main() {
prices := []int{10,20,30}
fmt.Println(prices[0])
fmt.Println(prices[2])
}
/*
10
30
*/
修改切片元素
通过引用索引号来修改特定的切片元素。
如下示例说明了如何修改切片中的第三个元素:
package main
import ("fmt")
func main() {
prices := []int{10,20,30}
prices[2] = 50
fmt.Println(prices[0])
fmt.Println(prices[2])
}
/*
10
50
*/
添加切片元素
使用 append()
函数将元素添加到切片的末尾:
语法
slice_name = append(slice_name, element1, element2, ...)
示例
如下示例说明了如何将元素添加到切片的末尾:
package main
import ("fmt")
func main() {
myslice1 := []int{1, 2, 3, 4, 5, 6}
fmt.Printf("myslice1 = %v\n", myslice1)
fmt.Printf("length = %d\n", len(myslice1))
fmt.Printf("capacity = %d\n", cap(myslice1))
myslice1 = append(myslice1, 20, 21)
fmt.Printf("myslice1 = %v\n", myslice1)
fmt.Printf("length = %d\n", len(myslice1))
// 为什么容量变成了 12 而不是 8 ?
fmt.Printf("capacity = %d\n", cap(myslice1))
}
/*
myslice1 = [1 2 3 4 5 6]
length = 6
capacity = 6
myslice1 = [1 2 3 4 5 6 20 21]
length = 8
capacity = 12
*/
添加一个切片到另一个切片
要将一个切片的所有元素附加到另一个切片,使用 append()
函数:
语法
slice3 = append(slice1, slice2...)
当 slice2 是一个切片时,即将一个切片添加到另一个切片时,slice2 后的 ...
是必须有的。
示例
package main
import ("fmt")
func main() {
myslice1 := []int{1,2,3}
myslice2 := []int{4,5,6}
myslice3 := append(myslice1, myslice2...)
fmt.Printf("myslice3=%v\n", myslice3)
fmt.Printf("length=%d\n", len(myslice3))
fmt.Printf("capacity=%d\n", cap(myslice3))
}
/*
myslice3=[1 2 3 4 5 6]
length=6
capacity=6
*/
修改切片长度
数组是固定长度的,但切片不是,切片可以修改其长度。以下示例说明了如何修改一个切片的长度:
package main
import ("fmt")
func main() {
arr1 := [6]int{9, 10, 11, 12, 13, 14} // An array
myslice1 := arr1[1:5] // Slice array
fmt.Printf("myslice1 = %v\n", myslice1)
fmt.Printf("length = %d\n", len(myslice1))
fmt.Printf("capacity = %d\n", cap(myslice1))
myslice1 = arr1[1:3] // Change length by re-slicing the array
fmt.Printf("myslice1 = %v\n", myslice1)
fmt.Printf("length = %d\n", len(myslice1))
fmt.Printf("capacity = %d\n", cap(myslice1))
myslice1 = append(myslice1, 20, 21, 22, 23) // Change length by appending items
fmt.Printf("myslice1 = %v\n", myslice1)
fmt.Printf("length = %d\n", len(myslice1))
fmt.Printf("capacity = %d\n", cap(myslice1))
}
/*
myslice1 = [10 11 12 13]
length = 4
capacity = 5
myslice1 = [10 11]
length = 2
capacity = 5
myslice1 = [10 11 20 21 22 23]
length = 6
capacity = 10
*/
内存效率
使用切片时,Go会将所有底层元素加载到内存中。
如果切片很大,并且只需要几个元素,那么最好使用 copy()
函数来复制这些元素。
copy()
函数创建一个新的底层数组,该数组只包含切片所需的元素。这将减少程序的内存消耗。
语法
copy(dest, src)
copy()
函数接收dest
和src
两个切片,并将数据从src
复制到dest
。它返回复制的元素数。
示例
package main
import ("fmt")
func main() {
numbers := []int{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}
// Original slice
fmt.Printf("numbers = %v\n", numbers)
fmt.Printf("length = %d\n", len(numbers))
fmt.Printf("capacity = %d\n", cap(numbers))
// Create copy with only needed numbers
neededNumbers := numbers[:len(numbers)-10]
numbersCopy := make([]int, len(neededNumbers))
copy(numbersCopy, neededNumbers)
fmt.Printf("numbersCopy = %v\n", numbersCopy)
fmt.Printf("length = %d\n", len(numbersCopy))
fmt.Printf("capacity = %d\n", cap(numbersCopy))
}
/*
// Original slice
numbers = [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15]
length = 15
capacity = 15
// New slice
numbersCopy = [1 2 3 4 5]
length = 5
capacity = 5
*/
运算符用于对变量和值执行运算。
+
运算符将两个值相加在一起,如下示例所示:
package main
import ("fmt")
func main() {
var a = 15 + 25
fmt.Println(a)
}
+
运算符也可以用于将变量和值相加,或将变量和另一个变量相加:
package main
import ("fmt")
func main() {
var (
sum1 = 100 + 50 // 150 (100 + 50)
sum2 = sum1 + 250 // 400 (150 + 250)
sum3 = sum2 + sum2 // 800 (400 + 400)
)
fmt.Println(sum3)
}
Go 语言中将运算符分为以下组:
- 算术运算符
- 赋值运算符
- 比较运算符
- 逻辑运算符
- 位运算符
Go 运算符
算术运算符
算术运算符用于执行常见的数学运算。
运算符 | 名称 | 描述 | 示例 | |
---|---|---|---|---|
+ | 加 | 将两个值相加 | x + y | |
- | 减 | 从另一个值中减去一个值 | x - y | |
* | 乘 | 将两个值相乘 | x * y | |
/ | 除 | 将一个值除以另一个值 | x / y | |
% | 求余 | 返回除法余数 | x % y | |
++ | 自增 | 将变量的值增加1 | x++ | |
-- | 自减 | 将变量的值减少1 | x-- |
示例
package main
import ("fmt")
func main() {
x:= 10
y:= 2
z:= 8
s:= 3
fmt.Println(x+y)
fmt.Println(x-y)
fmt.Println(x*y)
fmt.Println(x/y)
fmt.Println(z%s)
x++
fmt.Println(x)
y--
fmt.Println(y)
}
/*
12
8
20
5
2
11
1
*/
赋值运算符
赋值运算符用于为变量赋值。
所有赋值运算符如下:
运算符 | 示例 | 等同于 | |||
---|---|---|---|---|---|
= | x = 5 | x = 5 | |||
+= | x += 3 | x = x + 3 | |||
-= | x -= 3 | x = x - 3 | |||
*= | x *= 3 | x = x * 3 | |||
/= | x /= 3 | x = x / 3 | |||
%= | x %= 3 | x = x % 3 | |||
&= | x &= 3 | x = x & 3 | |||
\ | = | x\ | = 3 | x = x\ | 3 |
^= | x ^= 3 | x = x ^ 3 |
示例
package main
import ("fmt")
func main() {
var x = 5
fmt.Println(x)
x +=3
fmt.Println(x)
x -=3
fmt.Println(x)
x *= 3
fmt.Println(x)
x /= 3
fmt.Println(x)
x %= 3
fmt.Println(x)
// 重新设置x为5
x = 5
fmt.Printf("x is %b \n", x) // 101
fmt.Printf("3 is %03b \n", 3) // 011
x &= 3
fmt.Printf("x now is %03b \n", x) // 001
var x = 5
fmt.Printf("x is %b \n", x) // 101
fmt.Printf("3 is %03b \n", 3) // 011
x |= 3
fmt.Printf("x now is %03b \n", x) // 111
var x = 5
fmt.Printf("x is %b \n", x) // 101
fmt.Printf("3 is %03b \n", 3) // 011
x ^= 3
fmt.Printf("x now is %03b \n", x) // 110
var x = 5
fmt.Printf("x is %b \n", x) // 101
x >>= 3
fmt.Printf("x now is %03b \n", x) // 000
var x = 5
fmt.Printf("x is %b \n", x) // 101
x <<= 3
fmt.Printf("x now is %03b \n", x) // 101000
}
/*
5
8
5
15
5
2
x is 101
3 is 011
x now is 001
x is 101
3 is 011
x now is 111
x is 101
3 is 011
x now is 110
x is 101
x now is 000
x is 101
x now is 101000
*/
比较运算符
比较运算符用于比较两个值。
Note:比较的返回值为 true
(1)或 false
(0)。
在如下示例中,使用大于运算符(>)来确定 5 是否大于 3 :
package main
import ("fmt")
func main() {
var x = 5
var y = 3
fmt.Println(x>y) // returns 1 (true) because 5 is greater than 3
}
所有比较运算符如下表:
运算符 | 名称 | 示例 |
---|---|---|
== | 等于 | x == y |
!= | 不等于 | x != y |
> | 大于 | x > y |
< | 小于 | x < y |
>= | 大于或等于 | x >= y |
<= | 小于或等于 | x <= y |
示例
package main
import ("fmt")
func main() {
var x = 5
var y = 3
var z = 5
fmt.Println(x>y)
fmt.Println(x<y)
fmt.Println(x>=z)
fmt.Println(x<=y)
fmt.Println(x!=y)
fmt.Println(x==y)
}
/*
true
false
true
false
true
false
*/
逻辑运算符
逻辑运算符用于确定变量或值之间的逻辑:
运算符 | 名称 | 描述 | 示例 | ||||
---|---|---|---|---|---|---|---|
&& | 逻辑与 | 如果两个语句都为true,则返回true | x < 5 && x < 10 | ||||
\ | \ | 逻辑或 | 如果其中一个语句为true,则返回true | x < 5\ | \ | x < 4 | |
! | 逻辑非 | 反转结果,如果结果为true则返回false | !(x < 5 && x < 10) |
示例
package main
import ("fmt")
func main() {
var x = 5
fmt.Println(x < 5 && x < 10)
fmt.Println(x < 5 || x < 4)
fmt.Println(!(x < 5 && x < 10))
}
/*
false
false
true
*/
位运算符
按位运算符用于(二进制)数字:
运算符 | 名称 | 描述 | 示例 | ||
---|---|---|---|---|---|
& | AND | Sets each bit to 1 if both bits are 1 | x & y | ||
\ | OR | Sets each bit to 1 if one of two bits is 1 | x\ | y | |
^ | XOR | Sets each bit to 1 if only one of two bits is 1 | x ^ b | ||
<< | Zero fill left shift | Shift left by pushing zeros in from the right | x << 2 | ||
>> | Signed right shift | Shift right by pushing copies of the leftmost bit in from the left, and let the rightmost bits fall off | x >> 2 |
示例
package main
import ("fmt")
func main() {
var x = 9
var y = 8
fmt.Printf("x = %b\n",x)
fmt.Printf("y = %b\n",y)
fmt.Printf("x & y is %b\n",x & y)
fmt.Printf("x | y is %b\n",x | y)
fmt.Printf("x ^ y is %b\n",x ^ y)
fmt.Printf("x << 2 is %b\n",x << 2)
fmt.Printf("x >> 2 is %b\n",x >> 2)
}
/*
x = 1001
y = 1000
x & y is 1000
x | y is 1001
x ^ y is 1
x << 2 is 100100
x >> 2 is 10
*/
Go 条件语句
条件语句用于根据不同的条件选择执行不同的操作。
条件(Conditions)
条件的值是 true
或者 false
,或者对应值的表达式。
Go 支持数学中常见的比较运算符:
- 小于
<
- 小于或等于
<=
- 大于
>
- 大于或等于
>=
- 等于
==
- 不等于
!=
此外,Go 支持常见的逻辑运算符:
- 逻辑与
&&
- 逻辑或
||
- 逻辑非
!
可以使用这些运算符或它们的组合为不同的情况编写条件:
示例 | ||
---|---|---|
x > y | ||
x != y | ||
(x > y) && (y > z) | ||
(x == y)\ | \ | z |
Go 具有以下条件语句:
- 使用
if
指定条件为 true 时要执行的代码块 - 使用
else
指定上述条件为 false 时要执行的代码块 - 使用
else if
指定新的条件判断,用于上述if
条件为 false 时执行,并在新条件判断为 true 时运行指定的代码块 - 使用
switch
指定多个满足条件的可执行代码块
if 语句
如果条件为 true,则执行 if 语句指定 Go 代码块。
语法
if condition {
// code to be executed if condition is true
}
示例
如下示例中,判断条件 20 > 18
是否为 true, 如果该条件为 true, 打印文本:
package main
import ("fmt")
func main() {
if 20 > 18 {
fmt.Println("20 is greater than 18")
}
// 判断变量大小
x:= 20
y:= 18
if x > y {
fmt.Println("x is greater than y")
}
}
/*
20 is greater than 18
x is greater than y
*/
if else 语句
如果条件为 true,则执行 if 语句指定 Go 代码块,否则执行 else 语句指定的 Go 代码块。
语法
if condition {
// code to be executed if condition is true
} else {
// code to be executed if condition is false
}
示例
如下示例中,如果变量 time 的值小于 18 ,将会执行 if 指定的代码,打印出 "Good day",否则将会执行 else 指定的代码块,打印出 "Good evening."
package main
import ("fmt")
func main() {
time := 20
if (time < 18) {
fmt.Println("Good day.")
} else {
fmt.Println("Good evening.")
}
}
注意,在 else 语法中,花括号必须是 } else {
格式,否则会报错
package main
import ("fmt")
func main() {
temperature := 14
if (temperature > 15) {
fmt.Println("It is warm out there.")
} // this raises an error
else {
fmt.Println("It is cold out there.")
}
}
/*
./prog.go:9:3: syntax error: unexpected else, expecting }
*/
else if 语句
如果第一个条件为 false,可以使用 else if 语句指定一个新条件判断。
语法
if condition1 {
// code to be executed if condition1 is true
} else if condition2 {
// code to be executed if condition1 is false and condition2 is true
} else {
// code to be executed if condition1 and condition2 are both false
}
示例
package main
import ("fmt")
func main() {
time := 22
if time < 10 {
fmt.Println("Good morning.")
} else if time < 20 {
fmt.Println("Good day.")
} else {
fmt.Println("Good evening.")
}
}
/*
Good evening.
*/
在上面的例子中,time (22) 大于 10,因此第一个条件为 false。else if 语句中的下一个条件也是 false ,因此我们转到else条件,因为条件1和条件2都是false,并打印到屏幕上"Good evening"。如果 time 是14,程序将打印 "Good day."
嵌套 if 语句
在 if 语句中包含 if 语句,称为嵌套 if。
语法
if condition1 {
// code to be executed if condition1 is true
if condition2 {
// code to be executed if both condition1 and condition2 are true
}
}
示例
package main
import ("fmt")
func main() {
num := 20
if num >= 10 {
fmt.Println("Num is more than 10.")
if num > 15 {
fmt.Println("Num is also more than 15.")
}
} else {
fmt.Println("Num is less than 10.")
}
}
/*
Num is more than 10.
Num is also more than 15.
*/
Go switch 语句
使用 switch 语句可以从多个要执行的代码块中选择一个。
Go 中的 switch 语句与 C、C++、Java、JavaScript 和 PHP 中的类似。不同之处在于,它只运行匹配的 case,因此不需要 break 语句。
单值 switch 语法
语法
switch expression {
case x:
// code block
case y:
// code block
case z:
...
default:
// code block
}
工作原理说明:
- expression 求值一次
- 将
switch
expression 的值和每个case
的值进比较 - 如果匹配,则执行相关的代码块
default
是可选的. 用于指定没有任何case
匹配时执行的代码
示例
package main
import ("fmt")
func main() {
day := 4
switch day {
case 1:
fmt.Println("Monday")
case 2:
fmt.Println("Tuesday")
case 3:
fmt.Println("Wednesday")
case 4:
fmt.Println("Thursday")
case 5:
fmt.Println("Friday")
case 6:
fmt.Println("Saturday")
case 7:
fmt.Println("Sunday")
}
}
/*
Thursday
*/
default 关键字
default
关键字用于指定在没有 case
匹配的情况下要运行的代码:
package main
import ("fmt")
func main() {
day := 8
switch day {
case 1:
fmt.Println("Monday")
case 2:
fmt.Println("Tuesday")
case 3:
fmt.Println("Wednesday")
case 4:
fmt.Println("Thursday")
case 5:
fmt.Println("Friday")
case 6:
fmt.Println("Saturday")
case 7:
fmt.Println("Sunday")
default:
fmt.Println("Not a weekday")
}
}
/*
Not a weekday
*/
注意类型
所有 case
值都应具有与 switch
表达式相同的类型。否则,编译器将会报错:
package main
import ("fmt")
func main() {
a := 3
switch a {
case 1:
fmt.Println("a is one")
case "b":
fmt.Println("a is b")
}
}
/*
./prog.go:11:2: cannot use "b" (type untyped string) as type int
*/
多值 switch 语法
语法
switch 语句中的每个 case 都可以有多个值:
switch expression {
case x,y:
// code block if expression is evaluated to x or y
case v,w:
// code block if expression is evaluated to v or w
case z:
...
default:
// code block if expression is not found in any cases
}
示例
package main
import ("fmt")
func main() {
day := 5
switch day {
case 1,3,5:
fmt.Println("Odd weekday")
case 2,4:
fmt.Println("Even weekday")
case 6,7:
fmt.Println("Weekend")
default:
fmt.Println("Invalid day of day number")
}
}
/*
Odd weekday
*/
Go 循环语句
for 循环
for 循环会循环执行指定次数的内部代码块。 for 循环是 Go 语言中的唯一可用循环。
语法
如果想一次又一次地运行相同的代码,每次都使用不同的值,那么循环是最佳选择。
循环的每次执行都被称为迭代。
for 循环最多可以使用三个语句 (statement):
for statement1; statement2; statement3 {
// code to be executed for each iteration
}
示例 1
打印 0 到 4 之间的数字:
package main
import ("fmt")
func main() {
for i:=0; i < 5; i++ {
fmt.Println(i)
}
}
/*
0
1
2
3
4
*/
示例解释:
- i:=0; - 初始化循环计数器(i),并将起始值设置为0
- i < 5; - 只要 i 小于 5,就继续循环
- i++ - 每次迭代将循环计数器值增加 1
示例 2
在0-100,每隔10打印一次(输出100以内10的倍数):
package main
import ("fmt")
func main() {
for i:=0; i <= 100; i+=10 {
fmt.Println(i)
}
}
/*
0
10
20
30
40
50
60
70
80
90
100
*/
示例 2 说明:
- i:=0; - 初始化循环计数器(i),并将起始值设置为0
- i <= 100; - 只要 i 小于或等于 100 ,就继续循环
- i+=10 - 每次迭代将循环计数器值增加 10
continue
语句
continue 语句用于跳过循环中的一个或多个迭代。然后继续循环中的下一次迭代。
示例
跳过 3 :
package main
import ("fmt")
func main() {
for i:=0; i < 5; i++ {
if i == 3 {
continue
}
fmt.Println(i)
}
}
/*
0
1
2
4
*/
break
语句
break 语句用于中断/终止循环执行。
示例
当 i = 3 时中断循环,执行循环后的语句:
package main
import ("fmt")
func main() {
for i:=0; i < 5; i++ {
if i == 3 {
break
}
fmt.Println(i)
}
}
/*
0
1
2
*/
Note: continue 和 break 通常与条件一起使用。
嵌套循环
允许将一个循环放入另一个循环中,此时,内部循环会在外部循环的每一个迭代都执行一次:
package main
import ("fmt")
func main() {
adj := [2]string{"big", "tasty"}
fruits := [3]string{"apple", "orange", "banana"}
for i:=0; i < len(adj); i++ {
for j:=0; j < len(fruits); j++ {
fmt.Println(adj[i],fruits[j])
}
}
}
/*
big apple
big orange
big banana
tasty apple
tasty orange
tasty banana
*/
range
关键字
使用range
关键字可以更方便的对数组、切片或映射进行迭代。它同时返回索引和值。
语法
for index, value := array|slice|map {
// code to be executed for each iteration
}
示例
此示例使用 range 迭代数组,并打印每个数组的索引和值(idx存储索引,val存储值):
package main
import ("fmt")
func main() {
fruits := [3]string{"apple", "orange", "banana"}
for idx, val := range fruits {
fmt.Printf("%v\t%v\n", idx, val)
}
}
/*
0 apple
1 orange
2 banana
*/
如果只想使用值,不需要索引,那么可以将索引返回的变量使用 _
表示省略(反过来只使用索引不使用值类似):
package main
import ("fmt")
func main() {
fruits := [3]string{"apple", "orange", "banana"}
for _, val := range fruits {
fmt.Printf("%v\n", val)
}
}
/*
apple
orange
banana
*/
Go 函数
函数是一组可以在程序中重复使用的语句。
加载页时,函数不会自动执行。
函数将通过对该函数的调用来执行。
创建函数
语法
要创建(通常称为声明)函数,请执行以下操作:
- 使用
func
关键字. - 指定函数名, 后面跟着括号 ().
- 最后,在花括号{}内定义函数应该做什么的代码。
func FunctionName() {
// code to be executed
}
函数调用
函数不会立即执行。它们被“保存以供以后使用”,并将在调用时执行。
以下示例中,首先创建了一个名为 myMessage()
的函数。左花括号({
)表示函数代码的开始,右花括号(}
)表示函数的结束。函数输出 "I just got executed!" 。要调用该函数,只需将其名称后跟两个圆括号():
package main
import ("fmt")
func myMessage() {
fmt.Println("I just got executed!")
}
func main() {
myMessage() // call the function
}
/*
I just got executed!
*/
函数允许调用多次:
package main
import ("fmt")
func myMessage() {
fmt.Println("I just got executed!")
}
func main() {
myMessage() // call the function
myMessage()
myMessage()
}
/*
I just got executed!
I just got executed!
I just got executed!
*/
Go函数的命名规则
- 函数名必须以字母开头
- 函数名只能包含字母、数字字符和下划线(
A-z
、0-9
和_
) - 函数名区分大小写
- 函数名不能有空格
- 如果函数名由多个单词组成,可以沿用变量的多词命名规则
Tip: 函数名最好能够反映函数功能。
函数形参/实参
信息可以作为参数传递给函数。参数(形参)充当函数内部的变量。
参数及其类型在函数名后面的括号内指定。您可以添加任意数量的参数,只需用逗号将它们隔开:
func FunctionName(param1 type, param2 type, param3 type) {
// code to be executed
}
如下示例有一个函数,它有一个字符串类型的参数(fname)。当调用familyName()函数时,我们还传递一个名称(例如Liam),该名称用于函数内部,该函数输出几个不同的名字,但姓氏相同:
package main
import ("fmt")
func familyName(fname string) {
fmt.Println("Hello", fname, "Refsnes")
}
func main() {
familyName("Liam")
familyName("Jenny")
familyName("Anja")
}
/*
Hello Liam Refsnes
Hello Jenny Refsnes
Hello Anja Refsnes
*/
在函数内部,您可以添加任意数量的参数:
package main
import ("fmt")
// fname, age 为形式参数
func familyName(fname string, age int) {
fmt.Println("Hello", age, "year old", fname, "Refsnes")
}
func main() {
// "Liam", 3 为实际参数, 即实参,实参会传递给对应的形参
familyName("Liam", 3)
familyName("Jenny", 14)
familyName("Anja", 30)
}
/*
Hello 3 year old Liam Refsnes
Hello 14 year old Jenny Refsnes
Hello 30 year old Anja Refsnes
*/
注意调用函数时,传入的参数数量和顺序需要和定义一致。
函数返回
语法
如果希望函数返回值,则需要定义返回值的数据类型(如int、string等),并在函数内部使用 return
关键字:
func FunctionName(param1 type, param2 type) type {
// code to be executed
return output
}
如下示例中,myFunction()
接收两个整型参数(x
和 y
)并以整型格式(int
)返回这两个数的和(x + y
):
package main
import ("fmt")
func myFunction(x int, y int) int {
return x + y
}
func main() {
fmt.Println(myFunction(1, 2))
}
/*
3
*/
命名返回值
在 Go 语言中,可以在函数声明是命名返回值,函数内对该返回值变量赋值返回即可:
package main
import ("fmt")
func myFunction(x int, y int) (result int) {
result = x + y
return
// 也可以指定变量名返回,效果一样
// return result
}
func main() {
fmt.Println(myFunction(1, 2))
}
/*
3
*/
使用变量存储返回值
可以将返回值存储在变量中,如下所示,将函数返回值存储在 total
变量中:
package main
import ("fmt")
func myFunction(x int, y int) (result int) {
result = x + y
return
}
func main() {
total := myFunction(1, 2)
fmt.Println(total)
}
/*
3
*/
多个返回值
函数可以返回多个值。如下,函数 myFunction()
返回一个整型 (result
) 和一个字符串 (txt1
):
package main
import ("fmt")
func myFunction(x int, y string) (result int, txt1 string) {
result = x + x
txt1 = y + " World!"
return
}
func main() {
fmt.Println(myFunction(5, "Hello"))
// 用变量存储返回值如下:
// a, b := myFunction(5, "Hello")
// fmt.Println(a, b)
}
/*
10 Hello World!
*/
递归函数
Go 支持递归函数。如果函数调用自身并达到停止条件,则它是递归的。
如下示例中, testcount()
是一个调用自身的函数。 使用 x
变量作为数据, 在每次递归时增加 1 (x + 1
) , 递归的结束条件是单 x
等于 11 (x == 11
)。
package main
import ("fmt")
func testcount(x int) int {
if x == 11 {
return 0
}
fmt.Println(x)
return testcount(x + 1)
}
func main(){
testcount(1)
}
/*
1
2
3
4
5
6
7
8
9
10
*/
递归是一个常见的数学和编程概念。这样做的好处是,您可以重复执行相同步骤获得结果。
开发人员应该小心递归函数,因为编写一个永远不会终止的函数,或者一个使用过多内存或处理器能力的函数很容易出错。然而,如果写得正确,递归可能是一种非常高效且数学上优雅的编程方法。
在以下示例中,factorial_recursion()
是一个调用自身的函数。我们使用 x
变量作为数据,每次递归时它都会递减( -1 )。当条件不大于 0 时(即当条件为 0 时),递归结束。
package main
import ("fmt")
func factorial_recursion(x float64) (y float64) {
if x > 0 {
y = x * factorial_recursion(x-1)
} else {
y = 1
}
return
}
func main() {
fmt.Println(factorial_recursion(4))
}
Go 结构体
struct(structure 的缩写)用于将不同数据类型的成员集合创建为单个变量。
数组用于将同一数据类型的多个值存储到单个变量中,而结构体用于将不同数据类型的多个值存储到一个变量中。
结构体声明
在 Go 语言中,声明一个结构体需要使用 type
和 struct
关键字
type struct_name struct {
member1 datatype;
member2 datatype;
member3 datatype;
...
}
如下示例中,声明了一个 Person
结构体,包含几个成员:name
, age
, job
和 salary
:
type Person struct {
name string
age int
job string
salary int
}
访问结构体成员
要访问结构的任何成员,在结构变量名和结构成员之间使用点运算符(.
):
package main
import ("fmt")
type Person struct {
name string
age int
job string
salary int
}
func main() {
var pers1 Person
var pers2 Person
// Pers1 specification
pers1.name = "Hege"
pers1.age = 45
pers1.job = "Teacher"
pers1.salary = 6000
// Pers2 specification
pers2.name = "Cecilie"
pers2.age = 24
pers2.job = "Marketing"
pers2.salary = 4500
// Access and print Pers1 info
fmt.Println("Name: ", pers1.name)
fmt.Println("Age: ", pers1.age)
fmt.Println("Job: ", pers1.job)
fmt.Println("Salary: ", pers1.salary)
// Access and print Pers2 info
fmt.Println("Name: ", pers2.name)
fmt.Println("Age: ", pers2.age)
fmt.Println("Job: ", pers2.job)
fmt.Println("Salary: ", pers2.salary)
}
/*
Name: Hege
Age: 45
Job: Teacher
Salary: 6000
Name: Cecilie
Age: 24
Job: Marketing
Salary: 4500
*/
将结构体作为函数参数传递
可以将结构体作为函数参数传递,如下所示:
package main
import ("fmt")
type Person struct {
name string
age int
job string
salary int
}
func main() {
var pers1 Person
var pers2 Person
// Pers1 specification
pers1.name = "Hege"
pers1.age = 45
pers1.job = "Teacher"
pers1.salary = 6000
// Pers2 specification
pers2.name = "Cecilie"
pers2.age = 24
pers2.job = "Marketing"
pers2.salary = 4500
// Print Pers1 info by calling a function
printPerson(pers1)
// Print Pers2 info by calling a function
printPerson(pers2)
}
func printPerson(pers Person) {
fmt.Println("Name: ", pers.name)
fmt.Println("Age: ", pers.age)
fmt.Println("Job: ", pers.job)
fmt.Println("Salary: ", pers.salary)
}
/*
Name: Hege
Age: 45
Job: Teacher
Salary: 6000
Name: Cecilie
Age: 24
Job: Marketing
Salary: 4500
*/
Go Maps
- Map用于将数据值存储在键:值对中。
- Map中的每个元素都是一个键:值对。
- Map是一个无序且可更改的集合,不允许重复。
- Map的长度是其元素的数量。您可以使用len()函数找到它。
- Map的默认值为零。
- Map包含对基础哈希表的引用。
Go有多种创建Map的方法。
使用 var
和 :=
创建 Maps
语法
var a = map[KeyType]ValueType{key1:value1, key2:value2,...}
b := map[KeyType]ValueType{key1:value1, key2:value2,...}
示例
此示例显示如何在Go中创建maps。注意代码中的顺序和输出中的顺序:
package main
import ("fmt")
func main() {
var a = map[string]string{"brand": "Ford", "model": "Mustang", "year": "1964"}
b := map[string]int{"Oslo": 1, "Bergen": 2, "Trondheim": 3, "Stavanger": 4}
fmt.Printf("a\t%v\n", a)
fmt.Printf("b\t%v\n", b)
}
/*
a map[brand:Ford model:Mustang year:1964]
b map[Bergen:2 Oslo:1 Stavanger:4 Trondheim:3]
*/
使用 make()
函数创建 Maps
语法
var a = make(map[KeyType]ValueType)
b := make(map[KeyType]ValueType)
示例
package main
import ("fmt")
func main() {
var a = make(map[string]string) // The map is empty now
a["brand"] = "Ford"
a["model"] = "Mustang"
a["year"] = "1964"
// a is no longer empty
b := make(map[string]int)
b["Oslo"] = 1
b["Bergen"] = 2
b["Trondheim"] = 3
b["Stavanger"] = 4
fmt.Printf("a\t%v\n", a)
fmt.Printf("b\t%v\n", b)
}
/*
a map[brand:Ford model:Mustang year:1964]
b map[Bergen:2 Oslo:1 Stavanger:4 Trondheim:3]
*/
创建空 Map
有两种方式可以创建空 map。一种是使用 make()
函数,另一种是使用如下语法:
var a map[KeyType]ValueType
Note: make()
函数是创建空映射的正确方法。如果您以不同的方式制作一个空映射并对其进行写入,则会导致运行时死机。
package main
import ("fmt")
func main() {
var a = make(map[string]string)
var b map[string]string
fmt.Println(a == nil)
fmt.Println(b == nil)
}
/*
false
true
*/
允许的映射键类型
映射键可以是定义了等于运算符(==
)的任何数据类型。其中包括::
- Booleans
- Numbers
- Strings
- Arrays
- Pointers
- Structs
- Interfaces (as long as the dynamic type supports equality)
无效的映射键类型:
- Slices
- Maps
- Functions
因为这些类型内没有定义没有等于运算符(==
) 。
允许的值类型
映射值可以是任何类型。
访问 Map 元素
通过key访问,语法如下:
value = map_name[key]
示例如下:
package main
import ("fmt")
func main() {
var a = make(map[string]string)
a["brand"] = "Ford"
a["model"] = "Mustang"
a["year"] = "1964"
fmt.Printf(a["brand"])
}
/*
Ford
*/
更新和添加 Map 元素
语法
通过以下方式更新或添加元素:
map_name[key] = value
示例
package main
import ("fmt")
func main() {
var a = make(map[string]string)
a["brand"] = "Ford"
a["model"] = "Mustang"
a["year"] = "1964"
fmt.Println(a)
a["year"] = "1970" // Updating an element
a["color"] = "red" // Adding an element
fmt.Println(a)
}
/*
map[brand:Ford model:Mustang year:1964]
map[brand:Ford color:red model:Mustang year:1970]
*/
删除 Map 元素
语法
使用delete()
函数删除元素:
delete(map_name, key)
示例
package main
import ("fmt")
func main() {
var a = make(map[string]string)
a["brand"] = "Ford"
a["model"] = "Mustang"
a["year"] = "1964"
fmt.Println(a)
delete(a,"year")
fmt.Println(a)
}
/*
map[brand:Ford model:Mustang year:1964]
map[brand:Ford model:Mustang]
*/
检查 Map 中的特定元素
语法
可以使用以下方法检查映射中是否存在某个 Key:
val, ok :=map_name[key]
如果只想检查某个 key 是否存在,可以用空白标识符(_
)代替val。
示例
package main
import ("fmt")
func main() {
var a = map[string]string{"brand": "Ford", "model": "Mustang", "year": "1964", "day":""}
val1, ok1 := a["brand"] // Checking for existing key and its value
val2, ok2 := a["color"] // Checking for non-existing key and its value
val3, ok3 := a["day"] // Checking for existing key and its value
_, ok4 := a["model"] // Only checking for existing key and not its value
fmt.Println(val1, ok1)
fmt.Println(val2, ok2)
fmt.Println(val3, ok3)
fmt.Println(ok4)
}
/*
Ford true
false
true
true
*/
Note: 如何 key 不存在,返回的值会是空字符串 ''
Maps Are References
映射是对哈希表的引用。
如果两个映射变量引用同一个哈希表,则更改一个变量的内容会影响另一个的内容。
package main
import ("fmt")
func main() {
var a = map[string]string{"brand": "Ford", "model": "Mustang", "year": "1964"}
b := a
fmt.Println(a)
fmt.Println(b)
b["year"] = "1970"
fmt.Println("After change to b:")
fmt.Println(a)
fmt.Println(b)
}
/*
map[brand:Ford model:Mustang year:1964]
map[brand:Ford model:Mustang year:1964]
After change to b:
map[brand:Ford model:Mustang year:1970]
map[brand:Ford model:Mustang year:1970]
*/
Maps 遍历
可以使用 range
对 map 进行遍历:
package main
import ("fmt")
func main() {
a := map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}
for k, v := range a {
fmt.Printf("%v : %v, ", k, v)
}
}
/*
two : 2, three : 3, four : 4, one : 1,
*/
按特定顺序遍历 Maps
映射是无序的数据结构。如果需要按特定顺序迭代映射,则必须有一个单独的数据结构来指定该顺序。
package main
import ("fmt")
func main() {
a := map[string]int{"one": 1, "two": 2, "three": 3, "four": 4}
var b []string // defining the order
b = append(b, "one", "two", "three", "four")
for k, v := range a { // loop with no order
fmt.Printf("%v : %v, ", k, v)
}
fmt.Println()
for _, element := range b { // loop with the defined order
fmt.Printf("%v : %v, ", element, a[element])
}
}
/*
two : 2, three : 3, four : 4, one : 1,
one : 1, two : 2, three : 3, four : 4,
*/