一、go语言结构:
1.1.运行Hello World!
package main
import "fmt"
func main() {
fmt.Println("Hello World!")
}
二、go基础语法
2.1 fmt.Println会自动换行
package main
import "fmt"
func main() {
fmt.Println("Hello World!")
fmt.Println("hello world 自动换行")
}
2.2 注释
单行注释以//开头,多行注释以 /* 开头,并以 / 结尾
// 单行注释
/
我说多行注释1
我说多行注释2
我说多行注释3
*/
2.3 标识符
标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(AZ和az)数字(0~9)、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。
以下是有效的标识符:
mahesh kumar abc move_name a_123
myname50 _temp j a23b9 retVal
以下是无效的标识符:
- 1ab(以数字开头)
- case(Go 语言的关键字)
- a+b(运算符是不允许的)
2.4 字符串连接
Go 语言的字符串连接可以通过 + 实现:
package main
import "fmt"
func main() {
fmt.Println("golang"+"python")
}
2.5 关键字
下面列举了 Go 代码中会使用到的 25 个关键字或保留字:
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
2.6 格式化字符串
package main
import "fmt"
func main() {
var today string
today = "周二"
var day int
day = 3
fmt.Printf("%s是一周的第%d天",today,day)
}
三、变量
3.1 申明一个变量值,变量类型,并初始化
(1)两种方式,方式1:使用var声明
package main
import "fmt"
func main() {
var str string = "hello"
var num int = 123
println(str,num)
}
运行结果
(2)使用:=声明
package main
import "fmt"
func main() {
str := "hello"
num := 123
println(str,num)
}
运行结果
3.2 申请变量未初始化,则会给默认值
数值类型初始值0
布尔类型为fasle
字符串为""
其他类型为nil
package main
import "fmt"
func main() {
var num1 int
fmt.Println("num1的初始值为:",num1)
var str1 string
fmt.Println("str1的初始值为:",str1)
var flag bool
fmt.Println("flag的初始值为:",flag)
var a *int
var b []int
var c map[string] int
var d chan int
var e func(string) int
var f error
fmt.Println("a,b,c,d,e,f的初始值为:",a,b,c,d,e,f)
}
运行结果
3.3 根据值自行判定变量类型
package main
import "fmt"
func main() {
var str2 = "hello"
var num2 = 25
var flag2 = true
fmt.Println("str2的类型为:", reflect.TypeOf(str2))
fmt.Println("num2的类型为:", reflect.TypeOf(num2))
fmt.Println("flag2的类型为:", reflect.TypeOf(flag2))
}
运行结果
3.4 多变量声明
使用逗号隔开
package main
import "fmt"
func main() {
var num1,num2,num3 int = 4,6,8
fmt.Println("num1,num2,num3的值为:",num1,num2,num3)
}
运行结果
3.5 引用类型变量
&可查看引用变量的地址
package main
import "fmt"
func main() {
var num = 10
var str = "hello"
fmt.Println("num的值为:",num)
fmt.Println("num的引用为:",&num)
fmt.Println("str的值为:",str)
fmt.Println("str的应用为:",&str)
}
运行结果
四、常量
4.1 常量定义
常量是一个简单值的标识符,在程序运行时,不会被修改的量,使用const修饰一个常量
package main
import "fmt"
func main() {
const a string = "abc" //显示类型定义
const b = "abc" //隐示类型定义
const c, d = "o", "k"
println(a, b, c, d)
}
运行结果
4.2 常量还可以用作枚举
并且常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过
package main
import "fmt"
import "unsafe"
func main() {
const (
Unknown = 0
Female = 1
Male = 2
)
const (
a = "abc"
b = len(a)
c = unsafe.Sizeof(a) //16个字节,返回string结构体的字符与长度各8个字符相加
)
println(Unknown, Female, Male, a, b, c)
}
运行结果
4.3 特殊常量iota
iota,特殊常量,可以认为是一个可以被编译器修改的常量。
iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。
package main
import "fmt"
import "unsafe"
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)
}
运行结果
五、运算符
5.1 算数运算符
package main
import "fmt"
import "unsafe"
func main() {
a := 1
b := 2
fmt.Println("a加b等于:", a+b)
fmt.Println("a减b等于:", a-b)
fmt.Println("a剩b等于:", a*b)
fmt.Println("a除b等于:", a/b)
fmt.Println("a除b后取余数等于:", a%b)
a++
fmt.Println("a++后的结果:", a)
b--
fmt.Println("b--后的结果:", b)
}
运行结果
5.2 关系运算符
关系运算符主要有 =,!=,>,<,>=,<=共6种运算符
package main
import "fmt"
import "unsafe"
func main() {
var m int = 21
var n int = 10
if m == n {
fmt.Println("第一行返回:a等于b")
} else {
fmt.Println("第一行返回:a不等于b")
}
if m < n {
fmt.Println("第二行返回:a小于b")
} else {
fmt.Println("第二行返回:a不小于b")
}
if m > n {
fmt.Println("第三行返回:a大于b")
} else {
fmt.Println("第三行返回:a不大于b")
}
m, n = n, m //交换m,n的值
if m <= n {
fmt.Println("第四行返回:a小于等于b")
}
if m >= n {
fmt.Println("第四行返回:a不小于b")
}
}
运行结果
5.3 逻辑运算符
主要有三种逻辑运算符:
&&:逻辑 AND 运算符。 如果两边的操作数都是 True,则条件 True,否则为 False。
||:逻辑 OR 运算符。 如果两边的操作数有一个 True,则条件 True,否则为 False。
!:逻辑 NOT 运算符。 如果条件为 True,则逻辑 NOT 条件 False,否则为 True。
package main
import "fmt"
import "unsafe"
func main() {
var a bool = true
var b bool = false
if a && b {
fmt.Printf("第一行 - 条件为 true\n")
} else if a || b {
fmt.Printf("第一行 - 条件为 true\n")
}
a, b = b, a //修改a,b的值,对调
if a && b {
fmt.Printf("第二行 - 条件为 true\n")
} else {
fmt.Printf("第二行 - 条件为 false\n")
}
if !(a && b) {
fmt.Printf("第三行 - 条件为 true\n")
} else {
fmt.Printf("第三行 - 条件为 false\n")
}
}
运行结果
5.4 位运算符
位运算符对整数在内存中的二进制位进行操作。
&, |, ^ ,<<,>>四种位运算方式
package main
import "fmt"
import "unsafe"
func main() {
var a uint = 60 /* 60 = 0011 1100 */
var b uint = 13 /* 13 = 0000 1101 */
var c uint = 0
c = a & b /* 12 = 0000 1100 */
fmt.Printf("第一行 - c 的值为 %d\n", c)
c = a | b /* 61 = 0011 1101 */
fmt.Printf("第二行 - c 的值为 %d\n", c)
c = a ^ b /* 49 = 0011 0001 */
fmt.Printf("第三行 - c 的值为 %d\n", c)
c = a << 2 /* 240 = 1111 0000 */
fmt.Printf("第四行 - c 的值为 %d\n", c)
c = a >> 2 /* 15 = 0000 1111 */
fmt.Printf("第五行 - c 的值为 %d\n", c)
}
运行结果
5.5 赋值运算符
赋值符号为=,将一个表达式的值赋给一个左值,结合之前其他的型号的赋值运算符如下
package main
import "fmt"
import "unsafe"
func main() {
var a int = 21
var c int
c = a
fmt.Printf("第 1 行 - = 运算符实例,c 值为 = %d\n", c)
c += a
fmt.Printf("第 2 行 - += 运算符实例,c 值为 = %d\n", c)
c -= a
fmt.Printf("第 3 行 - -= 运算符实例,c 值为 = %d\n", c)
c *= a
fmt.Printf("第 4 行 - *= 运算符实例,c 值为 = %d\n", c)
c /= a
fmt.Printf("第 5 行 - /= 运算符实例,c 值为 = %d\n", c)
c = 200
c <<= 2
fmt.Printf("第 6行 - <<= 运算符实例,c 值为 = %d\n", c)
c >>= 2
fmt.Printf("第 7 行 - >>= 运算符实例,c 值为 = %d\n", c)
c &= 2
fmt.Printf("第 8 行 - &= 运算符实例,c 值为 = %d\n", c)
c ^= 2
fmt.Printf("第 9 行 - ^= 运算符实例,c 值为 = %d\n", c)
c |= 2
fmt.Printf("第 10 行 - |= 运算符实例,c 值为 = %d\n", c)
}
运行结果
六、条件语句
6.1 if else语句
package main
import "fmt"
import "unsafe"
func main() {
age := 18
if age < 5 {
fmt.Println("你的age为:", age, ",你太小了无法进入")
} else if age < 18 {
fmt.Println("你的age为:", age, ",你虽然不小了,但是仍然未满18,无法进入")
} else {
fmt.Println("你的age为:", age, ",你已满18岁,可以进入")
}
}
运行结果
6.2 if嵌套语句
计算可以数字a在0-100内,且是否可以被5整除
package main
import "fmt"
import "unsafe"
func main() {
a := 100
//if嵌套
if a <= 100 {
fmt.Println("a的值符合条件1:在0~100内,为:", a)
if a%5 == 0 {
fmt.Println("a的值符合条件2:可以被5整除,为:", a)
} else {
fmt.Println("a的值不符合条件2:不可以被5整除,为:", a)
}
} else {
fmt.Println("a的值不符合条件1:非在0~100内,为:", a)
}
}
运行结果
6.3 switch语句
6.3.1 switch+case语句:
switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。
witch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case
package main
import "fmt"
import "unsafe"
func main() {
score := 75
var grade string
switch {
case score < 60:
grade = "C"
case score >= 60 && score < 80:
grade = "B"
case score >= 80:
grade = "A"
}
fmt.Println(grade)
}
运行结果
6.3.2 switch+case+fallthrough:
使用 fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true。
package main
import "fmt"
import "unsafe"
func main() {
score := 90
var grade string
switch {
case score < 60:
grade = "C"
fallthrough
case false:
fmt.Println("使用fallthrough语句跳入到了下一步打印此句,因为您的成绩为:", grade)
case score >= 60 && score < 80:
grade = "B"
fallthrough
case false:
fmt.Println("使用fallthrough语句跳入到了下一步打印此句,因为您的成绩为:", grade)
case score >= 80:
grade = "A"
fallthrough
case false:
fmt.Println("使用fallthrough语句跳入到了下一步打印此句,因为您的成绩为:", grade)
}
fmt.Println(grade)
}
运行结果
6.3.3 switch+default:
defalut如果放在哪里是会最后执行
package main
import "fmt"
import "unsafe"
func main() {
score := 200
var grade string
switch {
default:
grade = "Nothing"
fmt.Printf("你的成绩为%d,并不合法,最终grade为%s", score, grade)
case score < 60:
grade = "C"
fallthrough
case false:
fmt.Println("使用fallthrough语句跳入到了下一步打印此句,因为您的成绩为:", grade)
case score >= 60 && score < 80:
grade = "B"
fallthrough
case false:
fmt.Println("使用fallthrough语句跳入到了下一步打印此句,因为您的成绩为:", grade)
case score >= 80 && score <= 100:
grade = "A"
fallthrough
case false:
fmt.Println("使用fallthrough语句跳入到了下一步打印此句,因为您的成绩为:", grade)
}
}
运行结果
6.4 select语句
select 是 Go 中的一个控制结构,类似于用于通信的 switch 语句。每个 case 必须是一个通信操作,要么是发送要么是接收。
select 随机执行一个可运行的 case。如果没有 case 可运行,它将阻塞,直到有 case 可运行。一个默认的子句应该总是可运行的。
package main
import "fmt"
import "unsafe"
func main() {
var c1, c2, c3 chan int
var i1, i2 int
select {
case i1 = <-c1:
fmt.Printf("received ", i1, " from c1\n")
case c2 <- i2:
fmt.Printf("sent ", i2, " to c2\n")
case i3, ok := (<-c3): // same as: i3, ok := <-c3
if ok {
fmt.Printf("received ", i3, " from c3\n")
} else {
fmt.Printf("c3 is closed\n")
}
default:
fmt.Printf("no communication\n")
}
}
运行结果
七、循环
7.1 for循环
7.1.1 for condition {}
package main
import "fmt"
import "unsafe"
func main() {
for i:=0;i<10;i++{
fmt.Println(i)
}
}
运行结果
7.1.1 for init {}
package main
import "fmt"
import "unsafe"
func main() {
Strings := []string{"google","baidu"}
for m,n := range Strings{
fmt.Println(m,n)
}
}
运行结果
7.2 循环嵌套
package main
import "fmt"
import "unsafe"
func main() {
var i, j int
for i = 2; i < 30; i++ {
for j = 2; j <= i/j; j++ {
if i%j == 0 {
break
}
}
if j > (i / j) {
fmt.Println(i, "是一个素数")
}
}
}
运行结果
7.3 break语句
7.3.1 用于循环语句中跳出循环,并开始执行循环之后的语句
package main
import "fmt"
import "unsafe"
func main() {
var a int = 10
for a < 20 {
fmt.Println("a的值:", a)
a++
if a == 15 {
break
}
}
}
运行结果
7.3.2 break 在 switch(开关语句)中在执行一条 case 后跳出语句的作用。(此break会隐藏)
7.3.3 在多重循环中,可以用标号 label 标出想 break 的循环
7.4 continue 语句
Go 语言的 continue 语句 有点像 break 语句。但是 continue 不是跳出循环,而是跳过当前循环执行下一次循环语句。
7.4.1 for 循环中,执行 continue 语句会触发 for 增量语句的执行
package main
import "fmt"
import "unsafe"
func main() {
a := 10
for a < 20 {
a++
if a == 15 {
continue
}
fmt.Println("a的值为:", a)
}
}
运行结果
7.5 goto 语句
Go 语言的 goto 语句可以无条件地转移到过程中指定的行。
goto 语句通常与条件语句配合使用。可用来实现条件转移, 构成循环,跳出循环体等功能。
package main
import "fmt"
import "unsafe"
func main() {
var a int = 10
/* 循环 */
LOOP:
for a < 20 {
if a == 15 {
a = a + 1
goto LOOP
}
fmt.Printf("a的值为 : %d\n", a)
a++
}
}
运行结果
八、函数
8.1 函数定义与调用
Go 语言最少有个 main() 函数。
你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。
函数定义解析:
- func:函数由 func 开始声明
- function_name:函数名称,参数列表和返回值类型构成了函数签名。
- parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
- return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。
- 函数体:函数定义的代码集合。
package main
import "fmt"
import "unsafe"
func max(num1, num2 int) int {
/* 声明局部变量 */
var result int
if num1 > num2 {
result = num1
} else {
result = num2
}
return result
}
func main() {
var a int = 98
var b int = 99
var c int = max(a, b)
fmt.Println("a,b两个数的最大值为:", c)
}
运行结果
8.2 函数返回多个值
package main
import "fmt"
import "unsafe"
func swap(x, y string) (string, string) {
x, y = y, x
return x, y
}
func main() {
x := "hello"
y := "world"
fmt.Println("交换前的x与y分别为:", x, y)
x, y = swap(x, y)
fmt.Println("交换后的x与y分别为:", x, y)
}
运行结果
8.3 值传递与引用传递
8.3.1 值传递
值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数
package main
import "fmt"
import "unsafe"
func swap(x, y string) (string, string) {
x, y = y, x
return x, y
}
func main() {
x := "hello"
y := "world"
fmt.Println("交换前的x与y分别为:", x, y)
x, y = swap(x, y)
fmt.Println("交换后的x与y分别为:", x, y)
}
运行结果
8.3.2 引用传递
引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数
package main
import "fmt"
import "unsafe"
func swap(x, y *string) string {
var temp string
temp = *x
*x = *y
*y = temp
return temp
}
func main() {
x := "hello"
y := "world"
fmt.Println("交换前的x与y分别为:", x, y)
swap(&x, &y)
fmt.Println("交换后的x与y分别为:", x, y)
}
运行结果
8.4 函数作为另外一个函数的实参(进阶ToDo)
8.5 闭包(进阶ToDo)
8.6 方法(进阶ToDo)
九、变量作用域
9.1 局部变量
函数内定义的变量称为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量
package main
import "fmt"
import "unsafe"
func main() {
var a, b, c int
/* 初始化参数 */
a = 10
b = 20
c = a + b
fmt.Printf("结果: a = %d, b = %d and c = %d\n", a, b, c)
}
运行结果
9.2 全局变量
函数外定义的变量称为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用
package main
import "fmt"
import "unsafe"
var g int
func main() {
/* 声明局部变量 */
var a, b int
/* 初始化参数 */
a = 10
b = 20
g = a + b
fmt.Printf("结果: a = %d, b = %d and g = %d\n", a, b, g)
}
运行结果
9.3 形式参数
形式参数会作为函数的局部变量来使用。实例如下:
package main
import "fmt"
///* 声明全局变量 */
//var g int
/* 声明全局变量 */
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
}
运行结果
9.4 初始化局部和全局变量
不同类型的局部和全局变量的默认值为:
int为0
float32为0
pointer为nil
十、数组
10.1 初始化局部和全局变量
例如以下定义了数组 balance 长度为 10 类型为 float32
var balance [10] float32
10.2 初始化数组
package main
import "fmt"
func main() {
//1.初始化数组
balance1 := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
fmt.Println(balance1)
//如果数组长度不确定,可以使用 ... 代替数组的长度,编译器会根据元素个数自行推断数组的长度:
balance2 := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
fmt.Println(balance2)
}
运行结果
10.3 访问数组元素
package main
import "fmt"
func main() {
//3.访问列表元素,通过for循环方式遍历
var n [10]int /* n 是一个长度为 10 的数组 */
var i, j int
/* 为数组 n 初始化元素 */
for i = 0; i < 10; i++ {
n[i] = i + 100 /* 设置元素为 i + 100 */
}
/* 输出每个数组元素的值 */
for j = 0; j < 10; j++ {
fmt.Printf("Element[%d] = %d\n", j, n[j])
}
}
运行结果
10.4 多维数组(进阶ToDo)
10.5 向函数传递数组(进阶ToDo)
十一、指针
11.1 指针的使用
一个指针变量指向了一个值的内存地址。
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)
}
运行结果
11.2 空指针
当一个指针被定义后没有分配到任何变量时,它的值为 nil。
nil 指针也称为空指针。
nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。
一个指针变量通常缩写为 ptr。
package main
import "fmt"
func main() {
//空指针
var ptr *int
fmt.Printf("ptr 的值为 : %x\n", ptr)
}
运行结果
11.3 指针数组(进阶ToDo)
11.4 指向指针的指针(进阶ToDo)
11.5 指针作为函数参数(进阶ToDo)
十二、结构体
12.1 定义结构体
Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
结构体定义需要使用 type 和 struct 语句。struct 语句定义一个新的数据类型,结构体中有一个或多个成员。type 语句设定了结构体的名称。
package main
import "fmt"
//定义结构体
type Books struct {
title string
author string
subject string
bookId int
}
func main() {
// 创建一个新的结构体
fmt.Println(Books{"Go 语言", "mr.white", "Go语言教程", 100001})
// 也可以使用 key => value 格式
fmt.Println(Books{title: "Go 语言", author: "mr.white", subject: "Go语言教程", bookId: 100002})
// 忽略的字段为 0 或 空
fmt.Println(Books{title: "Go 语言", author: "mr.white"})
}
运行结果
12.2 访问结构体成员
如果要访问结构体成员,需要使用点号 . 操作符。
package main
import "fmt"
// 定义结构体
type Book1 struct {
title string
author string
subject string
bookId int
}
type Book2 struct {
title string
author string
subject string
bookId int
}
func main() {
/* 创建 Book1 实例并赋值 */
book1 := Book1{
title: "Go 语言",
author: "mr.white",
subject: "Go 语言教程",
bookId: 100001,
}
/* 创建 Book2 实例并赋值 */
book2 := Book2{
title: "Python 教程",
author: "mr.white",
subject: "Python 语言教程",
bookId: 100002,
}
/* 打印 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.bookId)
/* 打印 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.bookId)
}
运行结果
12.3 结构体作为函数参数(进阶ToDo)
12.4 结构体指针(进阶ToDo)
十三、切片
13.1 定义/切片初始化
Go 数组的长度不可改变,在特定场景中这样的集合就不太适用,Go 中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
package main
import "fmt"
func main() {
//1.直接初始化切片,[] 表示是切片类型,{1,2,3} 初始化值依次是 1,2,3,其 cap=len=3。
s := []int{1, 2, 3}
fmt.Println("切片s:", s)
//初始化切片 s1,是数组 s 的引用。
s1 := s[:]
fmt.Println("切片s1:", s1)
//初始化切片 s2,是从下标 startIndex 到 endIndex-1 下的元素创建为一个新的切片。
s2 := s[1:3]
fmt.Println("切片s2:", s2)
//使用make初始化切片
s3 := make([]int, 3)
fmt.Println("切片s3:", s3)
}
运行结果
13.2 len() 和 cap() 函数
len() 方法获取切片的长度
cap()方法 可以测量切片最长可以达到多少
package main
import "fmt"
func printSlice(x []int) {
fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}
func main() {
//2调用printSlice方法获取切片的长度与容量
var numbers = make([]int, 3, 5)
printSlice(numbers)
}
运行结果
13.3 空(nil)切片
package main
import "fmt"
func printSlice(x []int) {
fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}
func main() {
//3.空切片
var numbers []int
printSlice(numbers)
if numbers == nil {
fmt.Println("切片是空的呢")
}
}
运行结果
13.4 切片截取
可以通过设置下限及上限来设置截取切片 [lower-bound:upper-bound],实例如下
package main
import "fmt"
func printSlice(x []int) {
fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}
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)
}
运行结果
13.5 append() 和 copy() 函数
如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。
下面的代码描述了从拷贝切片的 copy 方法和向切片追加新元素的 append 方法。
package main
import "fmt"
func printSlice(x []int) {
fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}
func main() {
//5.append() 和 copy() 函数
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)
}
运行结果
十四、范围(Range)
14.1 range的作用
range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引和索引对应的值,在集合中返回 key-value 对。
for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环
package main
import "fmt"
func main() {
map1 := make(map[int]float32)
map1[1] = 1.0
map1[2] = 2.0
map1[3] = 3.0
map1[4] = 4.0
// 读取 key 和 value
for key, value := range map1 {
fmt.Printf("key is: %d - value is: %f\n", key, value)
}
// 读取 key
for key := range map1 {
fmt.Printf("key is: %d\n", key)
}
// 读取 value
for _, value := range map1 {
fmt.Printf("value is: %f\n", value)
}
}
运行结果
十五、集合
15.1 定义 Map
/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type
/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)
实例如下:
package main
import "fmt"
func main() {
var countryCapitalMap map[string]string /*创建集合 */
countryCapitalMap = make(map[string]string)
/* map插入key - value对,各个国家对应的首都 */
countryCapitalMap["France"] = "巴黎"
countryCapitalMap["Italy"] = "罗马"
countryCapitalMap["Japan"] = "东京"
countryCapitalMap["India "] = "新德里"
/*使用键输出地图值 */
for country := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap[country])
}
/*查看元素在集合中是否存在 */
capital, ok := countryCapitalMap["American"] /*如果确定是真实的,则存在,否则不存在 */
/*fmt.Println(capital) */
/*fmt.Println(ok) */
if ok {
fmt.Println("American 的首都是", capital)
} else {
fmt.Println("American 的首都不存在")
}
}
运行结果
15.2 delete() 函数
delete() 函数用于删除集合的元素, 参数为 map 和其对应的 key。实例如下:
package main
import "fmt"
func main() {
//2.delete() 函数
/* 创建map */
countryCapitalMap := map[string]string{"France": "Paris", "Italy": "Rome", "Japan": "Tokyo", "India": "New delhi"}
fmt.Println("原始地图")
/* 打印地图 */
for country := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap[country])
}
/*删除元素*/
delete(countryCapitalMap, "France")
fmt.Println("法国条目被删除")
fmt.Println("删除元素后地图")
/*打印地图*/
for country := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap[country])
}
}
运行结果
十六、递归
Go 语言支持递归。但我们在使用递归时,开发者需要设置退出条件,否则递归将陷入无限循环中。
递归函数对于解决数学上的问题是非常有用的,就像计算阶乘,生成斐波那契数列等
16.1 阶乘
package main
import "fmt"
func Factorial(n uint64) (result uint64) {
if n > 0 {
result = n * Factorial(n-1)
return result
}
return 1
}
func main() {
//1.阶乘
var i int = 15
fmt.Printf("%d 的阶乘是 %d\n", i, Factorial(uint64(i)))
}
运行结果
16.2 斐波那契数列
package main
import "fmt"
func fibonacci(n int) int {
if n < 2 {
return n
}
return fibonacci(n-2) + fibonacci(n-1)
}
func main() {
//2.斐波那契数列
var i int
for i = 0; i < 10; i++ {
fmt.Printf("%d\t", fibonacci(i))
}
}
运行结果
十七、数据类型转换
17.1 转换规则
类型转换用于将一种数据类型的变量转换为另外一种类型的变量。Go 语言类型转换基本格式如下:
type_name(expression)
17.2 实例
package main
import "fmt"
func main() {
var sum int = 17
var count int = 5
var mean float32
mean = float32(sum)/float32(count)
fmt.Printf("mean 的值为: %f\n",mean)
}
运行结果
十八、接口
18.1 接口含义
Go 语言提供了另外一种数据类型即接口,它把所有的具有共性的方法定义在一起,任何其他类型只要实现了这些方法就是实现了这个接口。
18.2 实例
package main
import "fmt"
type Phone interface {
/* 定义结构体 */
call()
}
type NokiaPhone struct {
/* 定义结构体 */
}
func (nokiaPhone NokiaPhone) call() {
/* 实现接口方法 */
fmt.Println("I am Nokia, I can call you!")
}
type IPhone struct {
/* 定义结构体 */
}
func (iPhone IPhone) call() {
/* 实现接口方法 */
fmt.Println("I am iPhone, I can call you!")
}
func main() {
var phone Phone
phone = new(NokiaPhone)
phone.call()
phone = new(IPhone)
phone.call()
}
运行结果
十九、错误处理
19.1 error简介
Go 语言通过内置的错误接口提供了非常简单的错误处理机制。
type error interface {
Error() string
}
我们可以在编码中通过实现 error 接口类型来生成错误信息。
函数通常在最后的返回值中返回错误信息。使用errors.New 可返回一个错误信息:
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, errors.New("math: square root of negative number")
}
}
在下面的例子中,我们在调用Sqrt的时候传递的一个负数,然后就得到了non-nil的error对象,将此对象与nil比较,结果为true,所以fmt.Println(fmt包在处理error时会调用Error方法)被调用,以输出错误,请看下面调用的示例代码:
result, err:= Sqrt(-1)
if err != nil {
fmt.Println(err)
}
19.2 实例
package main
import "fmt"
// 定义一个 DivideError 结构
type DivideError struct {
dividee int
divider int
}
// 实现 `error` 接口
func (de *DivideError) Error() string {
strFormat := `
Cannot proceed, the divider is zero.
dividee: %d
divider: 0
`
return fmt.Sprintf(strFormat, de.dividee)
}
// 定义 `int` 类型除法运算的函数
func Divide(varDividee int, varDivider int) (result int, errorMsg string) {
if varDivider == 0 {
dData := DivideError{
dividee: varDividee,
divider: varDivider,
}
errorMsg = dData.Error()
return
} else {
return varDividee / varDivider, ""
}
}
func main() {
// 正常情况
if result, errorMsg := Divide(100, 10); errorMsg == "" {
fmt.Println("100/10 = ", result)
}
// 当除数为零的时候会返回错误信息
if _, errorMsg := Divide(100, 0); errorMsg != "" {
fmt.Println("errorMsg is: ", errorMsg)
}
}
运行结果
二十、接口
20.1并发介绍
Go 语言支持并发,我们只需要通过 go 关键字来开启 goroutine 即可。
goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的。
语句:go f(x, y, z)
如:开启一个新的 goroutine:
f(x, y, z)
18.2 实例
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
运行结果