参考文章 菜鸟教程
Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。对于高性能分布式系统领域而言,Go 语言无疑比大多数其它语言有着更高的开发效率。它提供了海量并行的支持,这对于游戏服务端的开发而言是再好不过了。
一、环境安装
安装包下载地址为 https://golang.org/dl/, 解压后将bin目录添加到环境变量,即可执行脚本 go run test.go
二、基础语法
Go 标记: Go 程序可以由多个标记组成,可以是关键字,标识符,常量,字符串,符号
包:package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
行分隔符:一行代表一个语句结束,如果你打算将多个语句写在同一行,它们则必须使用 ; 区分,但在实际开发中我们并不鼓励这种做法。
标识符:标识符用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母、数字、下划线组成的序列,而且标识符不能是关键字,以数字开头或包含运算符。有效的标识符: _temp、 a_123,无效的标识符:1ab、case、a+b
三、变量
1. 变量声明:
var a int = 10 // var a int; a=10; 指定变量类型,声明后若不赋值,使用默认值。 var a = 10 // 根据值自行判定变量类型。 a : = 10 // 省略var, 注意 :=左侧的变量若已经声明过会导致编译错误。这是使用变量的首选形式,但是它只能被用在函数体内,而不能用于全局变量的声明与赋值
如果你声明了一个局部变量却没有在相同的代码块中使用它,会得到编译错误。但是全局变量是允许声明但不使用。
2. 多变量声明
var a, b, c= 1, 2, 3
并行赋值也被用于当一个函数返回多个返回值时,如调用 Func1 函数得到val和err:val, err = Func1(var1)。
3. 值类型和引用类型:
像 int、float、bool 和 string 这些基本类型都属于值类型
一个引用类型的变量存储的是其值所在的内存地址,这个内存地址称为指针。* 表示指针变量,& 返回变量存储地址
var a int = 4 var ptr *int ptr = &a // ptr赋值为a变量的地址 fmt.Printf("a = %d\n", a); fmt.Printf("*ptr = %d\n", *ptr); fmt.Println("is null:", ptr == nil); // 判断是否为空指针
变量作用域
Go 语言中变量可以在三个地方声明:
- 局部变量:函数内定义的变量,返回值变量也是局部变量。
- 全局变量:函数外定义的变量,可以在整个包甚至外部包(被导出后)使用。
- 形式参数:函数定义中的变量,函数参数
package main import "fmt" var g int = 20 // 声明全局变量 func main() { var g int = 10 // 声明局部变量 fmt.Printf ("g = %d\n", g) // g = 10, 全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑 }
四、常量
常量是一个简单值的标识符,在程序运行时,不会被修改的量。常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
显式类型定义: const b string = "abc"
隐式类型定义: const b = "abc" // 可以省略 变量类型[type],编译器可以根据变量的值来推断其类型。
多个相同类型的声明可以简写为:const a, b= 1, 2
常量还可以用作枚举:
const ( Unknown = 0 Female = 1 Male = 2 )
常量可以用len(), cap(), unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数,否则编译不过:println(len(a),unsafe.Sizeof(a))
iota
iota是go语言的常量计数器,只能在常量的表达式中使用。iota在const关键字出现时将被重置为0(const内部的第一行之前),const中每新增一行常量声明将使iota计数一次(iota可理解为const语句块中的行索引)。
const a = iota // a=0 const ( b = iota // b=0 每次 const 出现时,都会让 iota 初始化为0. c // c=1 d = 3<<iota // d=3<<2=12 e // e=3<<3=24 d = "ha" // d="ha", iota=4 e // e="ha", iota=5 f = iota // f=6 )
五、条件和循环语句
六、数组
1. 声明格式:var variable_name [SIZE] variable_type
2. 数组初始化:
var numbers = [3]int{1, 2, 3}
var numbers = [] int{1, 2, 3} //不设置数组大小,根据元素的个数来设置大小
3. 二维数组:
var a [3][4]int a = [3][4]int{ {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}, }
4. 向函数传递数组
func main() { var numbers = []int {1, 2, 3, 4, 5} var avg float32 avg = getAverage(numbers, 5); fmt.Printf("Average: %f ", avg); } func getAverage(arr []int, size int) float32 { var i,sum int var avg float32 for i = 0; i < size;i++ { sum += arr[i] } avg = float32(sum / size) //类型转换 return avg; }
切片(slice)
Go 语言切片是对数组的抽象。Go 数组的长度不可改变,Go提供了一种功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。
切片定义:
声明一个未指定大小的数组: var identifier []type
或使用make()函数来创建切片: var slice1 []type = make([]type, len), 也可以简写为slice1 := make([]type, len)
也可以指定容量,其中capacity为可选参数。make([]T, length, capacity),这里 len 是数组的长度并且也是切片的初始长度。
切片初始化:
s :=[] int {1,2,3 }
s := arr[:] // 切片s为数组arr的引用。 切片截取:通过设置下限及上限来设置截取切片 s := arr[startIndex:endIndex] , s := arr[startIndex:] ,s := arr[:endIndex]
s :=make([]int,len,cap) //通过内置函数make()初始化切片s
func main() { var x []int // len=0 cap=0, slice=[], 一个切片在未初始化之前默认为 nil,长度为 0 x = make([]int,2,5) // len=2 cap=5, slice=[0 0] x = append(x, 10) // len=3 cap=5, slice=[0 0 10], 向切片添加一个元素 x = append(x, 11, 12) // len=5 cap=5, slice=[0 0 10 11 12], 向切片添加多个元素 x1 := make([]int, len(x), (cap(x))*2) // 创建切片x1是之前切片的两倍容量 copy(x1, x) // len=5 cap=10, slice=[0 0 10 11 12] } func printSlice(x []int) { fmt.Printf("len=%d cap=%d, slice=%v\n", len(x), cap(x), x) }
七、Map(集合)
八、结构体
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。
package main import "fmt" type Book struct { // 结构体定义 title string author string } func main() { var book1 Book book1.title = "Java" // 访问结构体成员 book1.author = "Thomas" printBook(book1) // Java {Java Thomas} printBook_ptr(&book1) // Java &{Java Thomas} } func printBook(b Book) { // 结构体作为函数参数 fmt.Println(b.title, b) } func printBook_ptr(b *Book) { // 结构体指针 fmt.Println(b.title, b) }
九、范围(Range)
十、函数
每一个可执行程序必须包含main() 函数,通常它是启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。
func main() { a, b := 1, 2 c,d := swap(a, b) e := getValue(a) fmt.Println(c, d, e) } func swap(a int, b int) (int, int){ // 多个返回值 return b, a } func getValue(a int) int { // 一个返回值 return a }
函数参数
package main import "fmt" func main() { x, y := 1, 2 val_swap(x, y) // 值传递 x=1 y=2 print(x, y) ref_swap(&x, &y) // 引用传递 x=2 y=1 print(x, y) } func val_swap(x int, y int) { var temp int temp = x x = y y = temp } func ref_swap(x *int, y *int){ var temp int temp = *x *x = *y *y = temp } func print(x int, y int) { fmt.Printf("x=%d y=%d\n", x, y) }
函数作为值
递归函数