golang高級語法及特點
golang特點
枚舉類型 iota
沒有char 只有rune
go語言所有類型都有默認值
原生支持複數類型
switch後可以沒有表達式
只有for 沒有while for可以不要條件 可以只有退出條件
函數沒有缺省參數
數組是值類型,調用func f(arr [10]int)會 拷貝 數組
go只有值傳遞沒有引用傳遞, 所以用指針類型來補充其他語言的引用傳遞
rune相當於go的char 使用utf8編碼,中文佔3個字節,英文一個字節
rune
package main
import "fmt"
//rune相當於go的char 使用utf8編碼,中文佔3個字節,英文一個字節
func main() {
s:= "ok我愛你"
fmt.Println(len(s)) // 11
fmt.Println(len([]rune(s))) // 5
fmt.Println(len([]byte(s))) // 11
// str是int32類型
for i, str := range s {
fmt.Printf("%d %c", i, str)
fmt.Println()
}
// str是byte類型
for i, str := range []byte(s) {
fmt.Printf("%d %x", i, str)
fmt.Println()
}
// str是rune類型
for i, str := range []rune(s) {
fmt.Printf("%d %c", i, str)
fmt.Println()
}
}
slice切片
slice的底層是數組
slice是對數組的view
slice可以向後擴展,不可以向前擴展
s[i]不可以超過len(s), 向後擴展不可以超越底層數組cap(s)
slice內部維持了3個變量,ptr指針指向slice的第一個元素,len指定了slice的長度,cap指定了slice的容量。
slice進行append時,容量不夠會進行翻倍。
有如下
arr := [...]{0, 1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6]
s2 := s1[3:5]
則
s1值爲[2,3,4,5], len(s1)=4, cap(s1)=6
s2值爲[5,6], len(s2)=2, cap(s2)=3
slice底層是數組
slice可以向後擴展,不可以向前擴展
s[i]不可以超過len(s), 向後擴展不可以超越底層數組cap(s)
接着上題
arr := [...]{0, 1, 2, 3, 4, 5, 6, 7}
s1 := arr[2:6]
s2 := s1[3:5]
s3 := append(s2, 10)
s4 := append(s3, 11)
s5 := append(s4, 12)
則
s1值爲[2,3,4,5]
s2值爲[5,6]
s3值爲[5,6,10]
s4值爲[5,6,10,11]
s5值爲[5,6,10,11,12]
arr值爲[0, 1, 2, 3, 4, 5, 6, 10]
由於s4和時s5已經超過arr的cap,此時系統會生成一個新的數組,所以s4和s5是對新數組的view,即s4和s5 no longer view arr
添加元素時如果超越cap,系統會重新分配更大的底層數組,原來的數組被拷貝過去,如果原來的數組沒人用則會被gc
由於值傳遞的關係,必須接受append的返回值
map
go語言所以類型都有默認值
當map取值的key不存在時,只會返回默認值,不會報錯。判斷key存不存在用 key, ok := m[“key”]
map使用哈希表,作爲map的key必須可以比較相等
除了slice,map, function的內建類型都可以作爲key
struce類型不包含上述字段,也可以作爲key
struct
只有使用指針纔可以改變結構體內容
nil指針也可以調用方法
如何擴充系統類型或者別人的類型:通過結構體繼承,通過類型起別名
package main
// 如何擴充系統類型或者別人的類型:通過結構體繼承,通過類型起別名
type queue []int
func (q *queue) push(v int) {
*q = append(*q, v)
}
func (q *queue) pop() int {
head := (*q)[0]
*q = (*q)[1:]
return head
}
func (q *queue) isEmpty() bool {
return len(*q) == 0
}
func main() {
}
值接受者vs指針接受者,
值接受者是go語言特有
要改變內容必須使用指針接受者,
結構過大也考慮使用指針接受者。
值/指針接受者都可以調用值/指針調用
package main
import "fmt"
type node struct {
value int
left, right *node
}
func newNode(value int) *node{
return &node{
value: value,
left: nil,
right: nil,
}
}
func (n node) setVal(val int) {
n.value = val
}
func (n *node) setValue(vall int) {
n.value = vall
}
func (n node) print() {
fmt.Println(n.value)
}
func (n *node) travel() {
if n == nil {
return
}
fmt.Println(n.value)
n.left.travel()
n.right.travel()
}
func main() {
var root node
root = node{}
root.left = &node{value:5}
root.right = new(node)
root.left.right = &node{4, nil, nil}
root.right.left = newNode(7)
// 調用指針方法,相當於引用傳遞,可以改變外部的值
root.left.setValue(100)
fmt.Println(root.left.value)
// 值傳遞,調用值方法,方法內部不能改變外部值
root.left.setVal(99)
fmt.Println(root.left.value)
// 先序遍歷
root.travel()
}
interface
defer