1. GO 环境安装
Windows系统
安装包下载地址为:golang.org/dl/ 或者 golang.google.cn/dl/
安装.msi文件
2. GO基础知识学习
语言数据类型
-
布尔型:
bool- 布尔型的值只可以是常量 true 或者 false
- 在格式化输出时,可以使用 %t 来表示你要输出的值为布尔型。
- 对于布尔值, 好的命名能够很好地提升代码的可读性,例如以 is 开头的isFinished。
var b bool = true -
数字类型:
- 数字类型的默认值是 0
- int 型是计算最快的一种类型
- Go是强类型语言,不会进行隐式转换。所以Go 中不允许不同类型之间的混合使用,但允许常量之间的混合使用。
- 尽可能地使用 float64,因为 math 包中所有有关数学运算的函数都会要求接收这个类型。
- 有符号整数
- int8(-128 -> 127)
- int16(-32768 -> 32767)
- int32(-2,147,483,648 -> 2,147,483,647)
- int64(-9,223,372,036,854,775,808 -> 9,223,372,036,854,775,807)
- int( 32 位操作系统上64 位,64 位操作系统64 位)
- 无符号整数
- uint8(0 -> 255)
- uint16(0 -> 65,535)
- uint32(0 -> 4,294,967,295)
- uint64(0 -> 18,446,744,073,709,551,615)
- uint ( 32 位操作系统上64 位,64 位操作系统64 位)
- 浮点数
- float32(+- 1e-45 -> +- 3.4 * 1e38)
- float64(+- 5 1e-324 -> 107 1e308)
- 复数
- complex64 (32 位实数和虚数)
- complex128 (64 位实数和虚数)
var a uint8 = 255 // 255 var b int = 255 // 255 var c int // 0 var d float64 //0 -
字符串类型:
string -
byte类型
-
rune类型
变量
- 变量通过变量名访问
- 变量名由字母、数字、下划线组成,其中数字不可以在守卫
- 声明变量使用
var, 可以一次性声明多个变量 - 声明变量的格式:
var identifier type, 可以只声明,不初始化. - 声明未初始化的时候不可以漏写类型, 否则会报错
- 单引号是字符, 会输出对应的 unicode编码, 双引号是字符串
省略 var, 格式为
i := 10, 需要注意的是:=的左侧必须是新的变量, 不能是已经声明过的,否则会产生编译错误,格式:
有效声明变量名如下
变量未初始化的初始值:
// 基本数据类型
package main
import "fmt"
func main() {
var i int
var f float64
var b bool
var s string
fmt.Printf("%v %v %v %q\n", i, f, b, s) // 0 0 false ""
}
// 其他数据
package main
import "fmt"
func main() {
var a *int // 报错: cannot use a (type *int) as type string in argument to fmt.Printf. Go build failed.
var b []int // []
var c map[string] int // map[]
var d chan int // <nil>
var e func(string) int // <nil>
var f error // <nil> error 是接口
fmt.Printf(a, b, c, d, e, f)
}
常量
常量是不会被修改值的标识符, 常量的数据类型只可以是布尔型、数字型和字符串型。
常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过
iota,特殊常量,可以认为是一个可以被编译器修改的常量, 它默认开始值是0,const中每增加一行加1,同行值相同, iota中断必须显性恢复,
// 定义如下:
const b string = "abc"
const b = "abc" // 编译器可以推断类型
const a, b, c = 1, false, "str" // 多值多类型定义
// 常量枚举
const (
Unknown = 0
Female = 1
Male = 2
)
// 函数计算式
a = "abc"
b = len(a)
// import "unsafe"
c = unsafe.Sizeof(a)
// iota
const (
a = iota
b
c
) // a = 0, b = 1, c= 2
// iota会存储常量的值
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
// iota实例
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
/**
i左移0位, j左移1位, k左移2位, l左移4位
<<n==*(2^n)
**/
运算符
Go 语言内置的运算符有:
- 算术运算符
- 关系运算符
- 逻辑运算符
- 位运算符
- 赋值运算符
- 其他运算符
算术运算符
| 运算符 | 描述 | 实例 |
|---|---|---|
| + | 相加 | 10 + 20 = 30 |
| - | 相减 | 10 - 20 = -10 |
| * | 相乘 | 10 * 20 = 200 |
| / | 相除 | 10 / 20 = 0.5 |
| % | 求余 | 10 % 20 = 10 |
| ++ | 自增 | 10++ = 11 |
| -- | 自减 | 10-- = 9 |
关系运算符
| 运算符 | 描述 | 实例 |
|---|---|---|
| == | 检查两个值是否相等,如果相等返回 true 否则返回 false | 1 == 1 // true |
| != | 检查两个值是否不相等,如果不相等返回 true 否则返回 false | 1 != 1 // false |
| 检查左边值是否大于右边值,如果是返回 true 否则返回 false | 1 > 1 false | |
| < | 检查左边值是否小于右边值,如果是返回 true 否则返回 false | 1 < 1 // false |
| >= | 检查左边值是否大于等于右边值,如果是返回 true 否则返回 false | 1 >= 1 // true |
| <= | 检查左边值是否小于等于右边值,如果是返回 true 否则返回 false | 1 <= 1 // true |
逻辑运算符
| 运算符 | 描述 | 实例 |
|---|---|---|
| &&(逻辑 AND 运算符) | 如果两边的操作数都是 true,则条件 true,否则为 false。 | true && false // false |
| || (逻辑 OR 运算符) | 相减 | false || false // false |
| !(逻辑 NOT 运算符) | 如果条件为 true,则逻辑 NOT 条件 false,否则为 true。 | !true // false |
位运算符
位运算符对整数在内存中的二进制位进行操作 位运算符 &, |, 和 ^ 的计算如下
| p | q | p & q | p | q | p ^ q |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 |
| 1 | 0 | 0 | 1 | 1 |
| 运算符 | 描述 | 实例 |
|---|---|---|
| & | 按位与运算符"&"是双目运算符。 其功能是参与运算的两数各对应的二进位相与。 | 1 & 1 // 1 |
| | | 按位或运算符"|"是双目运算符。 其功能是参与运算的两数各对应的二进位相或 | 0 | 1 // 1 |
| 按位异或运算符"^"是双目运算符。 其功能是参与运算的两数各对应的二进位相异或,当两对应的二进位相异时,结果为1。 | 0 ^ 1 // 1 , 1 ^ 1 // 0 | |
| << | 左移运算符"<<"是双目运算符。左移n位就是乘以2的n次方。 其功能把"<<"左边的运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0。 | 1 << 5 // 32 |
| >> | 右移运算符">>"是双目运算符。右移n位就是除以2的n次方。 其功能是把">>"左边的运算数的各二进位全部右移若干位,">>"右边的数指定移动的位数。 | 1 >> 5 // 0 |
赋值运算符
| 运算符 | 描述 | 实例 |
|---|---|---|
| = | 右边的值赋值到左边 | 实例 |
| += | 相加后再赋值 | a += 5 相当于 a = a + 5 |
| -= | 相减后再赋值 | a -= 5 相当于 a = a - 5 |
| *= | 相乘后再赋值 | a *= 5 相当于 a = a * 5 |
| /= | 相除后再赋值 | a /= 5 相当于 a = a / 5 |
| %= | 求余后再赋值 | a %= 5 相当于 a = a % 5 |
| <<= | 左移后赋值 | a <<= 5 相当于 a = a << 5 |
| >>= | 右移后赋值 | a >>= 5 相当于 a = a >> 5 |
| &= | 按位与后赋值 | a &= 5 相当于 a = a & 5 |
| ^= | 按位异或后赋值 | a ^= 5 相当于 a = a ^ 5 |
| |= | 按位或后赋值 | a |= 5 相当于 a = a | 5 |
其他运算符
| 运算符 | 描述 | 实例 |
|---|---|---|
| & | 返回变量存储地址 | 实例 |
| * | 指针变量 | &a : 变量a的内存地址 |
| -= | 相减后再赋值 | *a |
运算符优先级
优先级从上至下如下, 可以通过()改变优先级
| 优先级 | 运算符 |
|---|---|
| 5 | * / % << >> & &^ |
| 4 | + - | ^ |
| 3 | == != < <= > >= |
| 2 | && |
| 1 | || |
Go 语言条件语句
if
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
}
例子
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 10
/* 使用 if 语句判断布尔表达式 */
if a < 20 {
/* 如果条件为 true 则执行以下语句 */
fmt.Printf("a 小于 20\n" )
}
fmt.Printf("a 的值为 : %d\n", a)
}
// a 小于 20
// a 的值为 : 10
if...else
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
} else {
/* 在布尔表达式为 false 时执行 */
}
package main
import "fmt"
func main() {
/* 局部变量定义 */
var a int = 100;
/* 判断布尔表达式 */
if a < 20 {
/* 如果条件为 true 则执行以下语句 */
fmt.Printf("a 小于 20\n" );
} else {
/* 如果条件为 false 则执行以下语句 */
fmt.Printf("a 不小于 20\n" );
}
fmt.Printf("a 的值为 : %d\n", a);
}
// a 不小于 20
// a 的值为 : 10
if...else if
if 布尔表达式 1 {
/* 在布尔表达式 1 为 true 时执行 */
if 布尔表达式 2 {
/* 在布尔表达式 2 为 true 时执行 */
}
}
package main
import "fmt"
func main() {
/* 定义局部变量 */
var a int = 100
var b int = 200
/* 判断条件 */
if a == 100 {
/* if 条件语句为 true 执行 */
if b == 200 {
/* if 条件语句为 true 执行 */
fmt.Printf("a 的值为 100 , b 的值为 200\n" );
}
}
fmt.Printf("a 值为 : %d\n", a );
fmt.Printf("b 值为 : %d\n", b );
}
// a 的值为 100 , b 的值为 200
// a 值为 : 100
// b 值为 : 200
switch...case
- switch 语句用于基于不同条件执行不同动作,每一个 case 分支都是唯一的,从上至下逐一测试,直到匹配为止。
- switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break。
- switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,如果我们需要执行后面的 case,可以使用 fallthrough 。
- switch 支持多条件匹配
示例
package main
import "fmt"
func main() {
/* 定义局部变量 */
var grade string = "B"
var marks int = 90
switch marks {
case 90: grade = "A"
case 80: grade = "B"
// switch 支持多条件匹配
case 50,60,70 : grade = "C"
default: grade = "D"
}
switch {
case grade == "A" :
fmt.Printf("优秀!\n" )
case grade == "B", grade == "C" :
fmt.Printf("良好\n" )
case grade == "D" :
fmt.Printf("及格\n" )
case grade == "F":
fmt.Printf("不及格\n" )
default:
fmt.Printf("差\n" );
}
fmt.Printf("你的等级是 %s\n", grade );
// 优秀!
// 你的等级是 A
switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型。
package main
import "fmt"
func main() {
var x interface{}
switch i := x.(type) {
case nil:
fmt.Printf(" x 的类型 :%T",i)
case int:
fmt.Printf("x 是 int 型")
case float64:
fmt.Printf("x 是 float64 型")
case func(int) float64:
fmt.Printf("x 是 func(int) 型")
case bool, string:
fmt.Printf("x 是 bool 或 string 型" )
default:
fmt.Printf("未知型")
}
}
// x 的类型 :<nil>
使用 fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true。
package main
import "fmt"
func main() {
switch {
case false:
fmt.Println("1、case 条件语句为 false")
fallthrough
case true:
fmt.Println("2、case 条件语句为 true")
fallthrough
case false:
fmt.Println("3、case 条件语句为 false")
fallthrough
case true:
fmt.Println("4、case 条件语句为 true")
case false:
fmt.Println("5、case 条件语句为 false")
fallthrough
default:
fmt.Println("6、默认 case")
}
}
// 2、case 条件语句为 true
// 3、case 条件语句为 false
// 4、case 条件语句为 true
select
- select 是 Go 中的一个控制结构,类似于用于通信的 switch 语句。每个 case 必须是一个通信操作,要么是发送要么是接收。
- select 随机执行一个可运行的 case。会循环检测条件,如果有满足则执行并退出,否则一直循环检测(select阻塞)
- 多个case可执行, 只执行一个,其他不执行
语言循环语句
for循环可以嵌套
go 的几种for写法
// init: 一般为赋值表达式,给控制变量赋初值;
// condition: 关系表达式或逻辑表达式,循环控制条件;
// post: 一般为赋值表达式,给控制变量增量或减量。
// 类似 for(let i = 0; i < 10; i++) {}
// for init; condition; post { }
// condition为真时执行, 类似于 while
for condition { }
// 类似于 for(;;) 无限循环
for {}
计算1-10的和
// for init; condition; post { }
package main
import "fmt";
func main() {
sum := 0;
for i :=0; i <= 10; i++ {
sum += i
}
fmt.Println(sum)
}
for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:
for key, value := range oldMap { newMap[key] = value }
Go 语言函数
- Go 语言最少有个 main() 函数。
- 函数声明告诉了编译器函数的名称,返回类型,和参数。
/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
/* 声明局部变量 */
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}
// 函数返回多个值
func swap(x, y string) (string, string) {
return y, x
}
// 函数调用
a, b := swap("a", "b")
res := max(0, 1)
参数
参数分为值传递与引用传递. 值传递是复制到函数中,所以函数中,值改变, 实际参数不变 . 引用传递是在调用函数时候将引用函数地址传入函数, 所以, 函数参数修改, 实际参数会跟着改变
参数可以是任意值, 也可以是一个函数, 这样可以实现回调
语言变量作用域
| 作用域 | 定义 | 特点 |
|---|---|---|
| 全局变量 | 函数外定义的变量 | Go 语言程序中全局变量与局部变量名称可以相同,局部变量优先级 > 全局变量 |
| 局部变量 | 函数内定义的变量 | 作用域只在函数体内,参数和返回值变量也是局部变量 |
| 形式参数 | 函数定义中的变量 | 作为局部变量使用 |
Go 数组
数组是具有相同唯一类型的一组已编号且长度固定的数据项序列,可以是任意类型.
声明数组
var nums [10] float32 // 数组 nums 长度为 10 类型为 float32
初始化数组
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
balance := [5]float32{1.0, 2.0, 3.0, 4.0, 5.0}
// 不知道数组的长度可以用...代替 或者不写, 编译器会根据元素个数自行推断数组的长度
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0} // 数组长为5
balance := [...]float32{1.0, 2.0, 3.0, 4.0, 5.0} // 数组长为5
var balance = []float32{1000.0, 2.0, 3.4, 7.0, 50.0} // 数组长为5
balance := []float32{1.0, 2.0, 3.0, 4.0, 5.0} // 数组长为5
// 如果设置了数组的长度,还可以通过指定下标来初始化元素
var balance = [5]float32{1: 1.0, 2: 2.0, 3: 3.0} // 初始化索引为 1, 2, 3 的值:[0, 1, 2, 3, 0]
balance := [5]float32{1: 1.0, 2: 2.0, 3: 3.0} // [0, 1, 2, 3, 0]
balance[2] = 1.0 // [0, 1, 1, 3, 0]
访问数组元素
var a float32 = balance[1] // 取balance索引为1的第二位元素
Go 语言指针
声明指针变量
一个指针变量会指向一个值的内存地址, 声明如下:
var ip *int //整型
var fp *float32 // 浮点型
为指针变量赋值
var ip *int = &a
拿到变量的内存地址: &
Go 语言的取地址符是
&,放到一个变量前使用就会返回相应变量的内存地址。
package main
import "fmt"
func main() {
var a int = 10
fmt.Printf("a的地址是: %x\n", &a) // a的地址是: c000124008
}
访问指针变量中指向地址的值: *, 指针类型前面加上 * 号(前缀)来获取指针所指向的内容
package main
import "fmt"
func main() {
var a int = 10
var ip *int = &a
fmt.Printf("a 变量的地址是: %x\n", &a)
fmt.Printf("ip 变量储存的指针地址: %x\n", ip)
fmt.Printf("*ip 变量的值: %d\n", *ip)
}
// a 变量的地址是: c0000ae008
// ip 变量储存的指针地址: c0000ae008
// *ip 变量的值: 10
Go 空指针
当一个指针被定义后没有分配到任何变量时,它的值为 nil。nil 指针也称为空指针。指代空值或者零值
Go 语言结构体
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
定义结构体
// 定义了 一个 名为 书的结构体, 包含有title, author, subject, book_id属性
type Books struct {
title string
author string
subject string
book_id int
}
定义好的结构体可以用于声明变量
book1 := Books { "测试大全", "佚名", "软件工程", "4567" }
book2 := Books { title: "测试大全", author: "佚名", subject: "软件工程", book_id: "4567" }
// 忽略的字段为 0 或 空
book3 := Books { title: "测试大全", book_id: "4567" }
访问结构体成员
// 赋值
var Book1 Books
Book1.title = "Go 语言"
Book1.author = "www.runoob.com"
Book1.subject = "Go 语言教程"
Book1.book_id = 6495407
// 取值
fmt.Println(Book1.title) // Go 语言
Go 切片
Go 语言切片是对数组的抽象。切片是
Go内置类型切片("动态数组").与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
定义切片
var slice1 []string = make([]string, 5)
slice1 := make([]string, 5)
初始化
s :=[] int {1,2,3 }