GO语言基础
(有点开发基础是真的有点懒得写)
包声明
package main //包名,主函数
引入包
import "fmt" //格式化IO
函数
func main(){} //主函数
变量
var a int //不初始化默认为0 布尔则为false
var b string = "默认赋值"
var c = "字符串" //自动判断变量类型
d := 123 //一般用于局部变量定义
var (
e int
f string
) //一般用于全局变量声明
语句 & 表达式
fmt.Println("测试") //打印内容
注释
/*
注释
*/
// 注释
简单实例
package main
import "fmt"
func main(){
fmt.Println("测试")
}
常用语法(关键字)
break | default | func | interface | select |
case | defer | go | map | struct |
chan | else | goto | package | switch |
const | fallthrough | if | range | type |
continue | for | import | return | var |
append | bool | byte | cap | clone | complex | complex64 | complex128 | uint16 |
copy | false | float32 | float64 | imag | int | int8 | int16 | int32 |
int32 | int64 | iota | len | make | new | nil | panic | uint64 |
println | real | recover | string | true | uint | uint8 | uintptr |
Go语言空格
空格常用于分隔标识符、 关键字、运算符和表达式、提高代码可读性。
其中,变量的声明必须用空格隔开:
var a int
const Pi float64 = 3.14159265358979323846
关键字和表达式之间也要使用空格:
if a > 0 {
fmt.Println(a)
}
在调用函数时,函数名和左边等号之间要用空格,参数之间也要用空格。
result := add(2, 3)
Sprintf 根据格式化参数生成格式化的字符串并返回该字符串。
Printf 根据格式化参数生成格式化的字符串并写入标准输出。
package main
import (
"fmt"
)
func main() {
// %d 表示整型数字,%s 表示字符串
var stockcode=456
var enddate="2024-6-12"
var url="Code=%d&endDate=%s"
var target_url=fmt.Sprintf(url,stockcode,enddate)
fmt.Println(target_url)
}
输出结果:
Code=456&endDate=2024-6-12
实例:
package main
import (
"fmt"
)
func main() {
// %d 表示整型数字,%s 表示字符串
var stockcode=456
var enddate="2024-6-12"
var url="Code=%d&endDate=%s"
fmt.Printf(url,stockcode,enddate)
}
输出结果:
Code=456&endDate=2024-6-12
数据类型:
序号 | 类型和描述 |
1 | 布尔型 布尔型的值只可以是常量 true 或者 false。一个简单的例子:var b bool = true。 |
2 | 数字类型 整型 int 和浮点型 float32、float64,Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。 |
3 | 字符串类型: 字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。 |
4 | 派生类型: 包括:(a) 指针类型(Pointer) (b) 数组类型 (c) 结构化类型(struct) (d) Channel 类型 (e) 函数类型 (f) 切片类型 (g) 接口类型(interface) (h) Map 类型 |
数字类型:
序号 | 类型和描述 |
1 | uint8 无符号 8 位整型 (0 到 255) |
2 | uint16 无符号 16 位整型 (0 到 65535) |
3 | uint32 无符号 32 位整型 (0 到 4294967295) |
4 | uint64 无符号 64 位整型 (0 到 18446744073709551615) |
5 | int8 有符号 8 位整型 (-128 到 127) |
6 | int16 有符号 16 位整型 (-32768 到 32767) |
7 | int32 有符号 32 位整型 (-2147483648 到 2147483647) |
8 | int64 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807) |
浮点数
序号 | 类型和描述 |
1 | float32 IEEE-754 32位浮点型数 |
2 | float64 IEEE-754 64位浮点型数 |
3 | complex64 32 位实数和虚数 |
4 | complex128 64 位实数和虚数 |
其他数字类型
序号 | 类型和描述 |
1 | byte 类似 uint8 |
2 | rune 类似 int32 |
3 | uint 32 或 64 位 |
4 | int 与 uint 一样大小 |
5 | uintptr 无符号整型,用于存放一个指针 |
常量
定义格式:
const abc [type] = value
const a string = "abc" //定义类型
const b = "abc" //自动定义类型
const (
q = "abc"
w = len(q)
e = unsafe.Sizeof(a)
)
//结果为 abc 3 16
//unsafe.Sizeof返回的是数据类型的大小
//string在Go中并不是直存类型,而是一个结构体类型:
type StringHeader struct {
Data uintptr
Len int
}
iota
特殊常量,可以备注编译器修改的常量。
iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。
枚举值用法:
const (
a = iota
b = iota
c = iota
)
const (
a = iota
b
c
)
及a=0,b=1,c=2
实例1:
package main
import "fmt"
func main() {
const (
a = iota //0
b //1
c //2
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = 100 //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //8
)
fmt.Println(a,b,c,d,e,f,g,h,i)
}
//运行结果 0 1 2 ha ha 100 100 7 8
实例2:
package main
import "fmt"
const (
i=1<<iota
j=3<<iota
k
l
)
func main() {
fmt.Println("i=",i)
fmt.Println("j=",j)
fmt.Println("k=",k)
fmt.Println("l=",l)
}
//运行结果:
//i= 1
//j= 6
//k= 12
//l= 24
//iota 表示从 0 开始自动加 1,所以 i=1<<0, j=3<<1(<< 表示左移的意思),即:i=1, j=6,这没问题,关键在 k 和 l,从输出结果看 k=3<<2,l=3<<3。
解释:
- i=1:左移 0 位,不变仍为 1。
- j=3:左移 1 位,变为二进制 110,即 6。
- k=3:左移 2 位,变为二进制 1100,即 12。
- l=3:左移 3 位,变为二进制 11000,即 24。
注:<<n==*(2^n)。
算数运算符
算数运算符 | 描述 | 实例 |
+ | 相加 | A + B =30 |
– | 相减 | A – B = -10 |
* | 相乘 | A * B = 200 |
/ | 相除 | B / A = 2 |
% | 求余 | B % A = 0 |
++ | 自增 | A++ 为11 |
— | 自减 | A– 为9 |
关系运算符
运算符 | 描述 | 实例 |
== | 检查两个值是否相等,如果相等返回 True 否则返回 False。 | (A == B) 为 False |
!= | 检查两个值是否不相等,如果不相等返回 True 否则返回 False。 | (A != B) 为 True |
> | 检查左边值是否大于右边值,如果是返回 True 否则返回 False。 | (A > B) 为 False |
< | 检查左边值是否小于右边值,如果是返回 True 否则返回 False。 | (A < B) 为 True |
>= | 检查左边值是否大于等于右边值,如果是返回 True 否则返回 False。 | (A >= B) 为 False |
<= | 检查左边值是否小于等于右边值,如果是返回 True 否则返回 False。 | (A <= B) 为 True |
逻辑运算符
运算符 | 描述 | 实例 |
&& | 逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。 | (A && B) 为 False |
|| | 逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。 | (A || B) 为 True |
! | 逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。 | !(A && B) 为 True |
位运算符
运算符 | 描述 | 实例 |
& | 按位与运算符”&”是双目运算符。 其功能是参与运算的两数各对应的二进位相与。 | (A & B) 结果为 12, 二进制为 0000 1100 |
! | 按位或运算符”|”是双目运算符。 其功能是参与运算的两数各对应的二进位相或 | (A | B) 结果为 61, 二进制为 0011 1101 |
^ | 按位异或运算符”^”是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。 | (A ^ B) 结果为 49, 二进制为 0011 0001 |
<< | 左移运算符”<<“是双目运算符。左移n位就是乘以2的n次方。 其功能把”<<“左边的运算数的各二进位全部左移若干位,由”<<“右边的数指定移动的位数,高位丢弃,低位补0。 | A << 2 结果为 240 ,二进制为 1111 0000 |
>> | 右移运算符”>>”是双目运算符。右移n位就是除以2的n次方。 其功能是把”>>”左边的运算数的各二进位全部右移若干位,”>>”右边的数指定移动的位数。 | A >> 2 结果为 15 ,二进制为 0000 1111 |
赋值运算符
运算符 | 描述 | 实例 |
= | 简单的赋值运算符,将一个表达式的值赋给一个左值 | C = A + B 将 A + B 表达式结果赋值给 C |
+= | 相加后再赋值 | C += A 等于 C = C + A |
-= | 相减后再赋值 | C -= A 等于 C = C – A |
*= | 相乘后再赋值 | C *= A 等于 C = C * A |
/= | 相除后再赋值 | C /= A 等于 C = C / A |
%= | 求余后再赋值 | C %= A 等于 C = C % A |
<<= | 左移后赋值 | C <<= 2 等于 C = C << 2 |
>>= | 右移后赋值 | C >>= 2 等于 C = C >> 2 |
&= | 按位与后赋值 | C &= 2 等于 C = C & 2 |
^= | 按位异或后赋值 | C ^= 2 等于 C = C ^ 2 |
|= | 按位或后赋值 | C |= 2 等于 C = C | 2 |
其他运算符
运算符 | 描述 | 实例 |
& | 返回变量存储地址 | &a; 将给出变量的实际地址 |
* | 指针变量 | *a; 是一个指针变量 |
运算符优先级
优先级 | 运算符 |
5 | / % << >> & &^ |
4 | – | ^ |
3 | == != < <= > >= |
2 | && |
1 | || |
条件语句
语句 | 描述 |
if | if 语句 由一个布尔表达式后紧跟一个或多个语句组成。 |
if else | if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。 |
if 嵌套 | 你可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句。 |
switch | switch 语句用于基于不同条件执行不同动作。 |
select | select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。 |
循环语句
循环类型 | 描述 |
for | 重复执行语句块 |
循环嵌套 | 在 for 循环中嵌套一个或多个 for 循环 |
循环控制语句
控制语句 | 描述 |
break | 经常用于中断当前 for 循环或跳出 switch 语句 |
continue | 跳过当前循环的剩余语句,然后继续进行下一轮循环。 |
goto | 将控制转移到被标记的语句。 |
无限循环
package main
import "fmt"
func main() {
for true {
fmt.Printf("这是无限循环。\n");
}
}
函数
函数定义:
func function_name( [parameter list] ) [return_types] {
函数体
}
函数定义解析:
- func:函数由 func 开始声明
- function_name:函数名称,参数列表和返回值类型构成了函数签名。
- parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
- return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
- 函数体:函数定义的代码集合。
实例
/* 函数返回两个数的最大值 */
func max(num1, num2 int) int { //第一个int是num2 第二个int是函数返回值
/* 声明局部变量 */
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}
函数调用
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 100
var b int = 200
var ret int
/* 调用函数并返回最大值 */
ret = max(a, b)
fmt.Printf( "最大值是 : %d\n", ret )
}
/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
/* 定义局部变量 */
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}
函数范围多个值
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("445", "123")
fmt.Println(a, b)
}
函数参数
传递类型 | 描述 |
值传递 | 值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。 |
引用传递 | 引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。 |
函数用法
函数用法 | 描述 |
函数作为另外一个函数的实参 | 函数定义后可作为另外一个函数的实参数传入 |
闭包 | 闭包是匿名函数,可在动态编程中使用 |
方法 | 方法就是一个包含了接受者的函数 |
变量作用域
- 函数内定义的变量称为局部变量
- 函数外定义的变量称为全局变量
- 函数定义中的变量称为形式参数(形参)
实例:
package main
import "fmt"
/* 声明全局变量 */
var a int = 20;
func main() {
/* main 函数中声明局部变量 */
var a int = 10
var b int = 20
var c int = 0
fmt.Printf("main()函数中 a = %d\n", a);
c = sum( a, b);
fmt.Printf("main()函数中 c = %d\n", c);
}
/* 函数定义-两数相加 */
func sum(a, b int) int {
fmt.Printf("sum() 函数中 a = %d\n", a);
fmt.Printf("sum() 函数中 b = %d\n", b);
return a + b;
}
运行结果:
main()函数中 a = 10
sum() 函数中 a = 10
sum() 函数中 b = 20
main()函数中 c = 30
初始化局部和全部变量
数据类型 | 初始化默认值 |
int | 0 |
float32 | 0 |
pointer | nil |
数组

声明数组语法格式:
var arrayName [size]dataType
var abc [10]int //声明一个长度为10的数组abc,类型为int
var abc = [5]int{1,2,3,4,5} //初始化
abc := [5]int{1,2,3,4,5} //初始化
//注:在Go语言中,数组的大小是类型的一部分,不同大小的数组是不兼容的,[5]int和[10]int是不同的类型
//不确定长度可以使用...
var abc = [...]int{1,2,3}
abc := [...]int{1,2,3,4,5}
//指定初始化,将索引1和4的元素初始化
var abc = [5]int{1:3,4:11}
初始化数组中 {} 中的元素个数不能大于 [] 中的数字。
//如果忽略 [] 中的数字不设置数组大小,Go 语言会根据元素的个数来设置数组的大小
指针
go语言中,取地址符是&
package main
import "fmt"
func main() {
var a int = 10
fmt.Printf("变量的地址: %x\n", &a )
}
//运行结果:变量的地址:20818a220
指针的定义
一个指针变量指向了一个值的内存地址。
类似于变量和常量,在使用指针前需要声明指针。指针声明格式如下:
var var_name *var-type
//var-type 为指针类型,var_name 为指针变量名,* 号用于指定变量是作为一个指针。
var ip *int /* 指向整型*/
var fp *float32 /* 指向浮点型 */
指针使用流程:
- 定义指针变量。
- 为指针变量赋值。
- 访问指针变量中指向地址的值。
package main
import "fmt"
func main() {
var a int= 20 /* 声明实际变量 */
var ip *int /* 声明指针变量 */
ip = &a /* 指针变量的存储地址 */
fmt.Printf("a 变量的地址是: %x\n", &a )
/* 指针变量的存储地址 */
fmt.Printf("ip 变量储存的指针地址: %x\n", ip )
/* 使用指针访问值 */
fmt.Printf("*ip 变量的值: %d\n", *ip )
}
//a 变量的地址是: 20818a220
//ip 变量储存的指针地址: 20818a220
//*ip 变量的值: 20
空指针
当一个指针被定义后没有分配到任何变量时,它的值为 nil。
nil 指针也称为空指针。
nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。
一个指针变量通常缩写为 ptr。
package main
import "fmt"
func main() {
var ptr *int
fmt.Printf("ptr 的值为 : %x\n", ptr )
}
//ptr 的值为 : 0
if(ptr != nil) /* ptr 不是空指针 */
if(ptr == nil) /* ptr 是空指针 */
结构体
这个跟其他语言的结构体基本上一致。
定义结构体
type struct_variable_type struct {
member definition
member definition
...
member definition
}
定义了结构体后,声明变量的语法:
variable_name := structure_variable_type {value1, value2...valuen}
或
variable_name := structure_variable_type { key1: value1, key2: value2..., keyn: valuen}
实例:
package main
import "fmt"
type Books struct {
title string
author string
subject string
book_id int
}
func main() {
// 创建一个新的结构体
fmt.Println(Books{"Go 语言", "test", "测测", 123456})
// 也可以使用 key => value 格式
fmt.Println(Books{title: "Go 语言", author: "test", subject: "测测", book_id: 456789})
// 忽略的字段为 0 或 空
fmt.Println(Books{title: "Go 语言", author: "test"})
}
输出结果:
{Go 语言 test Go 测测 123456}
{Go 语言 test Go 测测 456789}
{Go 语言 test 0}
访问结构体成员
结构体.成员名
实例:
package main
import "fmt"
type Books struct {
title string
author string
subject string
book_id int
}
func main() {
var Book1 Books /* 声明 Book1 为 Books 类型 */
var Book2 Books /* 声明 Book2 为 Books 类型 */
/* book 1 描述 */
Book1.title = "Go 语言"
Book1.author = "test1"
Book1.subject = "测测"
Book1.book_id = 123456
/* book 2 描述 */
Book2.title = "坏鸟"
Book2.author = "test2"
Book2.subject = "测测"
Book2.book_id = 456789
/* 打印 Book1 信息 */
fmt.Printf( "Book 1 title : %s\n", Book1.title)
fmt.Printf( "Book 1 author : %s\n", Book1.author)
fmt.Printf( "Book 1 subject : %s\n", Book1.subject)
fmt.Printf( "Book 1 book_id : %d\n", Book1.book_id)
/* 打印 Book2 信息 */
fmt.Printf( "Book 2 title : %s\n", Book2.title)
fmt.Printf( "Book 2 author : %s\n", Book2.author)
fmt.Printf( "Book 2 subject : %s\n", Book2.subject)
fmt.Printf( "Book 2 book_id : %d\n", Book2.book_id)
}
运行结果:
Book 1 title : Go 语言
Book 1 author : test1
Book 1 subject : 测测
Book 1 book_id : 123456
Book 2 title : 坏鸟
Book 2 author : test2
Book 2 subject : 测测
Book 2 book_id : 456789
结构体作为函数参数
package main
import "fmt"
type Books struct {
title string
author string
subject string
book_id int
}
func main() {
var Book1 Books /* 声明 Book1 为 Books 类型 */
var Book2 Books /* 声明 Book2 为 Books 类型 */
/* book 1 描述 */
Book1.title = "Go 语言"
Book1.author = "test1"
Book1.subject = "测测"
Book1.book_id = 123456
/* book 2 描述 */
Book2.title = "坏鸟"
Book2.author = "test2"
Book2.subject = "测测"
Book2.book_id = 456789
/* 打印 Book1 信息 */
printBook(Book1)
/* 打印 Book2 信息 */
printBook(Book2)
}
func printBook( abc Books ) {
fmt.Printf( "Book title : %s\n", abc.title)
fmt.Printf( "Book author : %s\n", abc.author)
fmt.Printf( "Book subject : %s\n", abc.subject)
fmt.Printf( "Book book_id : %d\n", abc.book_id)
}
运行结果:
Book title : Go 语言
Book author : test1
Book subject : 测测
Book book_id : 123456
Book title : 坏鸟
Book author : test2
Book subject : 测测
Book book_id : 456789
结构体指针
结构体指针格式如下:
var struct_pointer *Books
以上定义的指针变量可以存储结构体变量的地址。查看结构体变量地址,可以将 & 符号放置于结构体变量前:
struct_pointer = &Book1
使用结构体指针访问结构体成员,使用 "." 操作符:
struct_pointer.title
实例:
package main
import "fmt"
type Books struct {
title string
author string
subject string
book_id int
}
func main() {
var Book1 Books /* 声明 Book1 为 Books 类型 */
var Book2 Books /* 声明 Book2 为 Books 类型 */
/* book 1 描述 */
Book1.title = "Go 语言"
Book1.author = "test1"
Book1.subject = "测测"
Book1.book_id = 123456
/* book 2 描述 */
Book2.title = "坏鸟"
Book2.author = "test2"
Book2.subject = "Python 语言教程"
Book2.book_id = 456789
/* 打印 Book1 信息 */
printBook(&Book1)
/* 打印 Book2 信息 */
printBook(&Book2)
}
func printBook( book *Books ) {
fmt.Printf( "Book title : %s\n", book.title)
fmt.Printf( "Book author : %s\n", book.author)
fmt.Printf( "Book subject : %s\n", book.subject)
fmt.Printf( "Book book_id : %d\n", book.book_id)
}
运行结果:
Book title : Go 语言
Book author : test1
Book subject : 测测
Book book_id : 123456
Book title : 坏鸟
Book author : test2
Book subject : 测测
Book book_id : 456789
切片
Go语言切片是对数组的抽象,在Go语言中,数组的长度是不可改变的,为了使其具有灵活性,Go语言提供了一个内置类型切片(“动态数组”),可以理解为不写长度的数组就是切片。
定义切片
切片不需要说明长度
var identifier []type
var slice1 []type = make([]type, len)
也可以简写为
slice1 := make([]type, len)
也可以指定容量,其中 capacity 为可选参数,意思是最大长度
make([]T, length, capacity)
这里 len 是数组的长度并且也是切片的初始长度
切片初始化
s :=[] int {1,2,3 }
直接初始化切片,[] 表示是切片类型,{1,2,3} 初始化值依次是 1,2,3,其 cap=len=3。
s := arr[:]
初始化切片 s,是数组 arr 的引用。
s := arr[startIndex:endIndex]
将 arr 中从下标 startIndex 到 endIndex-1 下的元素创建为一个新的切片。
s := arr[startIndex:]
默认 endIndex 时将表示一直到arr的最后一个元素。
s := arr[:endIndex]
默认 startIndex 时将表示从 arr 的第一个元素开始。
s1 := s[startIndex:endIndex]
通过切片 s 初始化切片 s1。
s :=make([]int,len,cap)
通过内置函数 make() 初始化切片s,[]int 标识为其元素类型为 int 的切片。
len()和cap()
len()获取长度,cap()测量切片最长可以达到多少。
package main
import "fmt"
func main() {
var numbers = make([]int,3,5)
printSlice(numbers)
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
输出结果:
len=3 cap=5 slice=[0 0 0]
空切片(nil)
一个切片在未初始化时默认为nil,长度为0
package main
import "fmt"
func main() {
var numbers []int
printSlice(numbers)
if(numbers == nil){
fmt.Printf("切片是空的")
}
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
输出结果:
len=0 cap=0 slice=[]
切片是空的
切片截取
package main
import "fmt"
func main() {
/* 创建切片 */
numbers := []int{0,1,2,3,4,5,6,7,8}
printSlice(numbers)
/* 打印原始切片 */
fmt.Println("numbers ==", numbers)
/* 打印子切片从索引1(包含) 到索引4(不包含)*/
fmt.Println("numbers[1:4] ==", numbers[1:4])
/* 默认下限为 0*/
fmt.Println("numbers[:3] ==", numbers[:3])
/* 默认上限为 len(s)*/
fmt.Println("numbers[4:] ==", numbers[4:])
numbers1 := make([]int,0,5)
printSlice(numbers1)
/* 打印子切片从索引 0(包含) 到索引 2(不包含) */
number2 := numbers[:2]
printSlice(number2)
/* 打印子切片从索引 2(包含) 到索引 5(不包含) */
number3 := numbers[2:5]
printSlice(number3)
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
运行结果:
len=9 cap=9 slice=[0 1 2 3 4 5 6 7 8]
numbers == [0 1 2 3 4 5 6 7 8]
numbers[1:4] == [1 2 3]
numbers[:3] == [0 1 2]
numbers[4:] == [4 5 6 7 8]
len=0 cap=5 slice=[]
len=2 cap=9 slice=[0 1]
len=3 cap=7 slice=[2 3 4]
append()和copy()
添加新元素append(),复制切片copy()
package main
import "fmt"
func main() {
var numbers []int
printSlice(numbers)
/* 允许追加空切片 */
numbers = append(numbers, 0)
printSlice(numbers)
/* 向切片添加一个元素 */
numbers = append(numbers, 1)
printSlice(numbers)
/* 同时添加多个元素 */
numbers = append(numbers, 2,3,4)
printSlice(numbers)
/* 创建切片 numbers1 是之前切片的两倍容量*/
numbers1 := make([]int, len(numbers), (cap(numbers))*2)
/* 拷贝 numbers 的内容到 numbers1 */
copy(numbers1,numbers)
printSlice(numbers1)
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
范围
跟python的差不多,一般用于for循环迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对。for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:
for key, value := range oldMap {
newMap[key] = value
}
只读key:
for key := range oldMap
for key, _ := range oldMap
只读value:
for _, value := range oldMap
类似于python的:
oldMap = {1:"a", 2: "b",3: "c"}
for key,value in oldMap.items():
abc[key] = value
实例
package main
import "fmt"
var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
func main() {
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
}
运行结果:
2**0 = 1
2**1 = 2
2**2 = 4
2**3 = 8
2**4 = 16
2**5 = 32
2**6 = 64
2**7 = 128
package main
import "fmt"
func main() {
//这是我们使用 range 去求一个 slice 的和。使用数组跟这个很类似
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
sum += num
}
fmt.Println("sum:", sum)
//在数组上使用 range 将传入索引和值两个变量。上面那个例子我们不需要使用该元素的序号,所以我们使用空白符"_"省略了。有时侯我们确实需要知道它的索引。
for i, num := range nums {
if num == 3 {
fmt.Println("index:", i)
}
}
//range 也可以用在 map 的键值对上。
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
//range也可以用来枚举 Unicode 字符串。第一个参数是字符的索引,第二个是字符(Unicode的值)本身。
for i, c := range "go" {
fmt.Println(i, c)
}
}
运行结果:
sum: 9
index: 1
a -> apple
b -> banana
0 103
1 111
Map集合
(相当于python的字典)
Map 是一种无序的键值对的集合。
Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,遍历 Map 时返回的键值对的顺序是不确定的。
在获取 Map 的值时,如果键不存在,返回该类型的零值,例如 int 类型的零值是 0,string 类型的零值是 “”。
Map 是引用类型,如果将一个 Map 传递给一个函数或赋值给另一个变量,它们都指向同一个底层数据结构,因此对 Map 的修改会影响到所有引用它的变量。
定义如下:
/* 使用 make 函数 */
map_variable := make(map[KeyType]ValueType, initialCapacity)
其中 KeyType 是键的类型,ValueType 是值的类型,initialCapacity 是可选的参数,用于指定 Map 的初始容量。Map 的容量是指 Map 中可以保存的键值对的数量,当 Map 中的键值对数量达到容量时,Map 会自动扩容。如果不指定 initialCapacity,Go 语言会根据实际情况选择一个合适的值。
// 创建一个空的 Map
m := make(map[string]int)
// 创建一个初始容量为 10 的 Map
m := make(map[string]int, 10)
// 使用字面量创建 Map
m := map[string]int{
"apple": 1,
"banana": 2,
"orange": 3,
}
// 获取键值对
v1 := m["apple"]
v2, ok := m["pear"] // 如果键不存在,ok 的值为 false,v2 的值为该类型的零值
// 修改键值对
m["apple"] = 5
// 获取 Map 的长度
len := len(m)
// 遍历 Map
for k, v := range m {
fmt.Printf("key=%s, value=%d\n", k, v)
}
// 删除键值对
delete(m, "banana")