go 语言学习笔记
“Go是一个开源的编程语言,它很容易用于构建简单、可靠和高效的软件。”(摘自Go语言官 方网站:http://golang.org )
Go语言不需要在语句或者声明的末尾添加分号,除非一行上有多条语句。实际上,编译器会主动把特定符号后的换行符转换为分号, 因此换行符添加的位置会影响Go代码的正确解析
- 函数的左括号必须位于函数名之后,且在行尾,不能独占一行,(其他相似情况下类似)
- 表达式x+y中,可以在+之后换行,不能在+之前换行
c类语言中i++为表达式,而go中,i++是语句而非表达式,且++i非法
*p++ //增加p指针指向的变量的值,而不改变p自身,与c/c++不同
复合类型
不同类型间不能进行直接赋值操作
数组
数组长度是数组类型的一部分,[3]int
和[4]int
属于不同类型
p := [3]int{1,2,3}
p = [4]int{1,2,3,4} //error
函数的所有形参包括数组在内都是采用副本的形式传入
func test(a [4]int)[4]int{
for i,j := range a{
a[i] = j+1
}
return a
}
func main() {
var a = [4]int{1,2,3,4}
fmt.Println(a) //1,2,3,4
var b = test(a)
fmt.Println(a) //1,2,3,4
fmt.Println(b) //2,3,4,5
}
slice
切片声明时不需要指定大小,系统自动生成
s := []int{1,2,3,4} //与数组不同,不需要指定大小
值为nil
的slice没有底层数组,与nil相等的slice长度为0,当长度为0的slice不一定是nil
var s []int // len(s) == 0, s == nil
s = nil // len(s) == 0, s == nil
s = []int(nil) // len(s) == 0, s == nil
s = []int{} // len(s) == 0, s != nil
内置的make函数创建一个指定元素类型、长度和容量的slice。容量部分可以省略,在这种情况下,容量将等于长度。
make([]T, len)
make([]T, len, cap) // same as make([]T, cap)[:len]
内置的append函数用于向slice追加元素:
var runes []rune
for _, r := range "Hello, 世界" {
runes = append(runes, r)
}
fmt.Printf("%q\n", runes) // "['H' 'e' 'l' 'l' 'o' ',' ' ' '世' '界']"
结构体
一个结构体可能同时含有导出成员和未导出成员
点操作符也可以和指向结构体的指针一起工作:
var employeeOfTheMonth *Employee = &dilbert
employeeOfTheMonth.Position += " (proactive team player)"
相当于下面语句
(*employeeOfTheMonth).Position += " (proactive team player)"
结构体比较
若结构的所有成员都是可比较的,则结构体是可比较的当结构体所有成员都相等时,结构体变量相等
嵌入和匿名
结构体可以嵌入到另一个结构体中
匿名成员的数据类型必须是命名的类型或指向一个命名的类型的指针
对于匿名嵌入,可以直接访问叶子属性而不需要给出完整的路径
type Point struct { X, Y int } type Circle struct { Point Radius int } type Wheel struct { Circle Spokes int } var w Wheel w.X = 8 // equivalent to w.Circle.Point.X = 8 w.Y = 8 // equivalent to w.Circle.Point.Y = 8 w.Radius = 5 // equivalent to w.Circle.Radius = 5 w.Spokes = 20
函数
声明
以下4中声明所代表的含义相同
func add(x int, y int) int {return x + y} func sub(x, y int) (z int) { z = x - y; return} func first(x int, _ int) int { return x } func zero(int, int) int { return 0 } fmt.Printf("%T\n", add) // "func(int, int) int" fmt.Printf("%T\n", sub) // "func(int, int) int" fmt.Printf("%T\n", first) // "func(int, int) int" fmt.Printf("%T\n", zero) // "func(int, int) int"
返回值
go支持多个返回值
如果一个函数将所有的返回值都显示的变量名,那么该函数的return语句可以省略操作数。这
称之为bare return。// CountWordsAndImages does an HTTP GET request for the HTML // document url and returns the number of words and images in it. func CountWordsAndImages(url string) (words, images int, err error) { resp, err := http.Get(url) if err != nil { return } doc, err := html.Parse(resp.Body) resp.Body.Close() if err != nil { err = fmt.Errorf("parsing HTML: %s", err) return } words, images = countWordsAndImages(doc) return } func countWordsAndImages(n *html.Node) (words, images int) { /* ... */ }
函数值
在GO中,函数被看作第一类值:函数拥有类型,可以赋值给其他变量,传递给函数,从函数返回
但是函数值之间是不可比较的,也不能用函数值作为map的key。
匿名函数
拥有函数名的函数只能在包级语法块中被声明,通过函数字面量(function literal),我们可绕过这一限制,在任何表达式中表示一个函数值。函数字面量的语法和函数声明相似,区别在于func关键字后没有函数名。函数值字面量是一种表达式,它的值被称为匿名函数(anonymous function),也称闭包。
,通过这种方式定义的函数可以访问完整的词法环境(lexical environment),
这意味着在函数中定义的内部函数可以引用该函数的变量,如下例所示:// squares返回一个匿名函数。 // 该匿名函数每次被调用时都会返回下一个数的平方。 func squar