环境变量配置
GOPATH
GOPATH是作为编译后二进制的存放目的地和import包时的搜索路径, 即工程目录, 主要包含三个目录: bin、pkg、src
比如 C:\Users\administrator\Desktop\temporary\calcproj
GOROOT
GOROOT就是go的安装路径
~/.bash_profile中配置如下
GOROOT=/usr/local/go
export $PATH:$GOROOT/bin
命令行工具
go run hello.go # 直接运行,使用这个命令,会将编译、链接和运行3个步骤合并为一步,运行完后在当前目录下也看不到任何中间文件和最终的可执行文件
go build hello.go & ./hello # 生成编译结果而不自动运行
go test simplemath # 测试
变量声明
var v1 int
var v2 string
var v3 [10]int // 数组
var v4 []int // 数组切片
var v5 struct { //结构体
f int
}
var v6 *int // 指针
var v7 map[string]int // map, key为string类型, value为int类型
var v8 func(a int) int
结构体的定义与使用
type PersonInfo struct {
ID string
Name string
Address string
}
var aa = PersonInfo{"12345", "Tom", "Room 203,..."}
变量初始化
var v1 int = 10 // 正确的使用方式1
var v2 = 10 // 正确的使用方式2,编译器可以自动推导出v2的类型
v3 := 10 // 正确的使用方式3,编译器可以自动推导出v3的类型,冒号和等号的组合 := 用于明确表达同时进行变量声明和初始化的工作
匿名变量
在调用函数时为了获取一个值,却因为该函数返回多个值而不得不定义一堆没用的变量。在Go中这种情况可以通过结合使用多重返回和匿名变量来避免这种丑陋的写法,让代码看起来更加优雅
假 设 GetName() 函 数 的 定 义 如 下 , 它 返 回 3 个 值 , 分 别 为firstName 、 lastName 和nickName:
func GetName() (firstName, lastName, nickName string) {
return "May", "Chan", "Chibi Maruko"
}
若只想获得nickName,则函数调用语句可以用如下方式编写:
_, _, nickName := GetName()
常量
const Pi float64 = 3.14159265358979323846
const zero = 0.0 // 无类型浮点常量
const u, v float32 = 0, 3 // u = 0.0, v = 3.0,常量的多重赋值
const a, b, c = 3, 4, "foo" //无类型整型和字符串常量
const mask = 1 << 3
枚举
const (
Sunday = iota //iota比较特殊,可以被认为是一个可被编译器修改的常量,在每一个const关键字出现时被重置为0,然后在下一个const出现之前,每出现一次iota,其所代表的数字会自动增1
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
numberOfDays // 这个常量没有导出
)
同Go语言的其他符号(symbol)一样,以大写字母开头的常量在包外可见。以上例子中numberOfDays为包内私有,其他符号则可被其他包访问
布尔类型
var v1 bool
v1 = true
v2 := (1 == 2) // v2也会被推导为bool类型
位运算
x << y 左移 124 << 2 // 结果为496
x >> y 右移 124 >> 2 // 结果为31
x ^ y 异或 124 ^ 2 // 结果为126
x & y 与 124 & 2 // 结果为0
x | y 或 124 | 2 // 结果为126
^x 取反 ^2 // 结果为3
浮点数比较
因为浮点数不是一种精确的表达方式,所以像整型那样直接用==来判断两个浮点数是否相等是不可行的,这可能会导致不稳定的结果。
下面是一种推荐的替代方案:
import "math"
// p为用户自定义的比较精度,比如0.00001
func IsEqual(f1, f2, p float64) bool {
return math.Fdim(f1, f2) < p
}
字符串遍历
func main() {
str := "Hello,世界"
for i, ch := range str { //索引一个字符串,得到的是byte,而不是字符
// fmt.Println(i, ch) //ch的类型为rune
fmt.Printf("index=%d, %#U\n", i, ch) //ch的类型为rune, 使用%#U打印utf-8的字符
}
}
数组
在Go语言中数组是一个值类型(value type), 所有的值类型变量在赋值和作为参数传递时都将产生一次复制动作
数组声明方法:
a := [4] byte {} // 长度为32的数组,每个元素为一个字节
c := [3] * float64 {} // 指针数组
d := [2][3] int {} // 二维数组
e := [2][2][2] float64 {} // 等同于[2]([2]([2]float64))
数组遍历
for i, v := range array {
fmt.Println("Array element[", i, "]=", v)
}
数组切片
可以随时动态扩充存放空间,并且可以被随意传递而不会导致所管理的元素被重复复制
创建数组切片--基于数组
var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
var mySlice []int = myArray[:5] //基于数组创建一个数组切片
创建数组切片--直接创建
mySlice1 := make([]int, 5) //创建一个初始元素个数为5的数组切片,元素初始值为0
mySlice2 := make([]int, 5, 10) //创建一个初始元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间
mySlice3 := []int{1, 2, 3, 4, 5} //直接创建并初始化包含5个元素的数组切片
数组切片方法
cap()函数返回的是数组切片分配的空间大小,而len()函数返回的是数组切片中当前所存储的元素个数
mySlice := make([]int, 5, 10)
fmt.Println("len(mySlice):", len(mySlice))
fmt.Println("cap(mySlice):", cap(mySlice))
数组切片新增元素
mySlice = append(mySlice, 1, 2, 3)
mySlice = append(mySlice, mySlice2...) //我们在第二个参数mySlice2后面加了三个点,即一个省略号,如果没有这个省略号的话,会有编译错误,因为按append()的语义,从第二个参数起的所有参数都是待附加的元素。因为mySlice中的元素类型为int,所以直接传递mySlice2是行不通的。加上省略号相当于把mySlice2包含的所有元素打散后传入
数组切片内容复制
数组切片支持Go语言的另一个内置函数copy(),用于将内容从一个数组切片复制到另一个数组切片。如果加入的两个数组切片不一样大,就会按其中较小的那个数组切片的元素个数进行复制。下面的示例展示了copy()函数的行为
slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{5, 4, 3}
copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中
copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置
map
type PersonInfo struct {
ID string
Name string
Address string
}
func main() {
var personDB map[string] PersonInfo // 声明map
personDB = make(map[string] PersonInfo) // 创建map
personDB["12345"] = PersonInfo{"12345", "Tom", "Room 203,..."} //插入几条数据
person, ok := personDB["1234"] // 从这个map查找键为"1234"的信息, ok是一个返回的bool型,返回true表示找到了对应的数据
}
创建了一个初始存储能力为100的map
myMap = make(map[string] PersonInfo, 100)
创建并初始化map的代码如下
myMap = map[string] PersonInfo{
"1234": PersonInfo{"1", "Jack", "Room 101,..."},
}
元素删除
delete(myMap, "1234")
流程控制
条件语句
if a < 5 {
fmt.Println(1)
} else {
fmt.Println(2)
}
在有返回值的函数中,不允许将“最终的” return语句包含在if...else...结构中
循环语句
sum := 0
for i := 0; i < 10; i++ {
sum += i
}
无限循环
sum := 0
for {
sum++
if sum > 100 {
break
}
}
提供了一个更高级的break,可以选择中断哪一个循环
func main() {
JLoop:
for j := 0; j < 5; j++ {
for i := 0; i < 10; i++ {
if i > 5 {
break JLoop // break语句终止的是JLoop标签处的外层循环
}
fmt.Println(i)
}
}
}
跳转语句
func main() {
i := 0
HERE:
fmt.Println(i)
i++
if i < 10 {
goto HERE
}
}
有疑问加站长微信联系(非本文作者)