Go 語言學(xué)習(xí)的入門部分草讶,如果有C語言的基礎(chǔ)類比學(xué)習(xí)會非常迅速÷疲總結(jié)來說 Go語言 和 C語言很相似堕战,語法更為簡單,所以寫起來會相對迅速很多拍霜。以下是基礎(chǔ)語法的筆記践啄。
>教程來自 http://www.yiibai.com/go/go_start.html
感謝博主的精心編寫。
導(dǎo)入包
import "fmt"
import "math"
或者下面:
import (
"fmt"
"math"
)
導(dǎo)出名字
go 中沉御,首字母大寫名稱是被導(dǎo)出的屿讽。全小寫的名字是不會被導(dǎo)出。
fmt.Println(math.Pi) //這里PI 改為 pi 就是不可以的吠裆。
函數(shù)
func add(x int ,y int) int {
return x + y
}
或者
func add(x,y int) int {
return x + y
}
函數(shù)中命名返回值
func split (sum int )(x,y int){
x = sum * 4 /9 ;
y = sum - x ;
return ;
}
變量
變量定義看起來頗為隨意伐谈,很方便。
var c, python , java = true , false , "no!"
var i , j int = 1 , 2
func main(){
fmt.Println(i,j,c,python,java)
}
變量在函數(shù)內(nèi)還可以去掉var等關(guān)鍵字试疙,直接退化為如下操作:
func main(){
var i , j int = 1 , 2
k := 3
c , python , java = true , false , "no!"
fmt.Println(i,j,k,c,python,java)
}
基本數(shù)據(jù)類型
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
byte //uint8 別名
rune //int32 的別名
//代表一個unicode碼
float32 float64
complex64 complex128
int,uint,uintptr在32位系統(tǒng)上是32位诵棵,而在64位系統(tǒng)上是64位。一般直接使用int就可以了祝旷。一般僅有特定理由才用定長整型或者無符號整型履澳。
var (
ToBe bool = false
MaxInt uint64 = 1<<64 - 1
z complex128 = cmplx.Sqrt(-5 + 12i)
)
func main(){
const f = "%T(%v)\n"
fmt.Printf(f,z,z)
fmt.Printf(f,MaxInt,MaxInt)
fmt.Printf(f,ToBe,ToBe)
}
零值
變量在定義時候沒有明確的初始化時會賦值為零值.
數(shù)值類型為 **0**
布爾類型為 **false**
字符串為 "" **空字符串**
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)
}
類型轉(zhuǎn)換
表達式T(v)將值v轉(zhuǎn)換為類型T。
一些關(guān)于數(shù)值的轉(zhuǎn)換
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
//或者更為簡單的形式
i := 42
f := float64(i)
u := uint(f)
類型推導(dǎo)
在定義一個變量卻并不顯式指定其類型的時候(使用 := 語法或者 var =表達式語法),變量的類型由(等號)右側(cè)的值推導(dǎo)得出.
當右值定義了類型時候,新變量的類型與其相同:
var i int
j := i // j也是一個int
當時當右邊包含了未指明類型的數(shù)字常量時候怀跛,新的變量就可能是int距贷、float64或complex128 。 這取決于常量的精度:
i := 42 //int
f := 3.142 //float64
g := 0.867 + 0.5i //complex128
常量
常量的定義與變量類似吻谋,只不過使用 const 關(guān)鍵字忠蝗。
常量可以是字符、字符串漓拾、布爾或數(shù)字類型的值阁最。
常量不能使用 := 語法定義。
package main
import "fmt"
const Pi = 3.14
func main(){
const World = "世界"
fmt.Println("Hello",World)
fmt.Println("Happy",Pi,"Day")
const Truth = true
fmt.Println("Go rules?",Truth)
}
數(shù)值常量
數(shù)值常量是高精度的值骇两。
一個未指定類型的常量由上下文來決定其類型速种。
也嘗試一下輸出 needInt(Big) 吧。(int 可以存放最大64位的整數(shù)低千,根據(jù)平臺的不同有時會更少配阵。)
const(
Big = 1 << 100
small = Big >> 99
)
func needInt(x int) int {return x * 10 + 1}
func needFloat(x float64) float64 {
return x * 0.1
}
控制流
for
Go 只有一種循環(huán)結(jié)構(gòu) --- for循環(huán)。這點和C比較相似。具體如下:
func main(){
sum : = 0
for i := 0 ; i < 10 ; i++ {
sum += i
}
fmt.Println(sum)
}
其中循環(huán)初始化語句和后置語句都是可選的:
func main(){
sum := 1
for ; sum < 1000 ; {
sum += sum
}
fmt.Println(sum)
}
這里和C語言很相似闸餐,但是不需要括號饱亮,如果有括號反而會報錯矾芙。
for 也可以變成 C語言的中while
func main(){
sum := 1
for sum < 1000 {
sum += sum
}
fmt.Println(sum)
}
或者變?yōu)樗姥h(huán)
func main(){
for { //無退出條件舍沙,變成死循環(huán)
}
}
if
就像 for循環(huán)一樣,Go 的 if語句也不要求用 ()括號括起來剔宪,但是 {} 大括號表示作用域的內(nèi)容還是必須要有的拂铡。
func sqrt(x float64) string {
if x<0 {
return sqrt(-x) + "i"
}
return fmt.Sprint(math.Sqrt(x))
}
if的便捷語句
跟 for語句一樣,if語句可以在條件之前執(zhí)行一個簡單的語句葱绒。由這個語句定義的變量的作用域僅在 if 范圍之內(nèi)感帅。
func pow(x,n,lim float64) float64 {
if v := math.Pow(x,n); v < lim {
return v
}
return lim
}
if和else
在 if 的便捷語句定義的變量同樣可以在任何對應(yīng)的else塊中使用。(提示:兩個 pow 都在main 中調(diào)用 fmt.Println 前執(zhí)行完了)
func pow(x,n,lim float64) float64 {
if v:math.Pow(x,n); v<lim{
return v
} else {
fmt.Printf("%g >= %g\n",v,lim)
}
return lim
}
swith語句
switch除非以 fallthrough 語句結(jié)束地淀,否則分支會自動終止失球。
switch os: rumtime.GOOS ; os{
case "darwin":
fmt.Println("OS X")
case "linux":
fmt.Println("Linux")
default:
//freebsd , openbsd,
//plan9,windows...
fmt.Printf("%s.",os)
}
switch 的執(zhí)行順序
switch 的條件從上到下執(zhí)行,當匹配成功的時候停止帮毁。
switch i {
case 0 :
case f():
}
//當i==0時候不會調(diào)用 **f()**
today := time.Now().Weekday()
switch time.Saturday {
case today + 0 :
fmt.Println("Today.")
case today + 1:
fmt.Println("Tomorrow")
case today + 2:
fmt.Println("In two days")
default:
fmt.Println("Too far away")
}
沒有條件的swtich
沒有條件的switch 同 switch true一樣实苞。這一構(gòu)造使得可以用更清晰的形式來編寫長的if-then-else 鏈。
t := time.Now()
switch {
case t.Hour() < 12 :
fmt.Println("Good morning!")
case t.Hour() < 17 :
fmt.Println("Good afternoon!")
default:
fmt.Println("Good evening.")
}
defer 語句
defer 語句會延遲函數(shù)的執(zhí)行烈疚,直到上層函數(shù)返回黔牵。延遲調(diào)用的參數(shù)會立即生成,但是在上層函數(shù)返回前函數(shù)都不會調(diào)用爷肝。
func main(){
defer fmt.Println("world")
fmt.Println("hello")
}
defer 棧
延遲函數(shù)調(diào)用被壓入一個棧中猾浦。當函數(shù)后進先出的順序調(diào)用被延遲的函數(shù)調(diào)用。
fmt.Println("counting")
for i:= 0 ; i<10 ; i++{
defer fmt.Println(i)
}
fmt.Println("done")
指針
go 具有指針灯抛。指針保存了變量的內(nèi)存地址金赦。
類型 *T 是執(zhí)行類型為 T 的指針,其零值是 nil对嚼。
var p *int
&符號會生成一個指向其作用對象的指針素邪。
i := 42
p = &i
* 符號表示指針指向的底層的值。
fmt.Println(*p) //通過指針p讀取i
*p = 21 //通過指針p設(shè)置i
這也就是通常所說的“間接引用”或“非直接引用”猪半。
與C不同兔朦,Go 沒有指針運算。
i磨确,j := 100 , 666
p := &i
fmt.Println(*p) //通過p讀取I的值
*p = 777
fmt.Println(i)
p = &j
*p = *p / 37
fmt.Println(j)
結(jié)構(gòu)體字段
結(jié)構(gòu)體字段使用點號來訪問(這點和C很像)
type Vertex struct {
X int
Y int
}
func main(){
v:= Vertex(1,2)
v.X = 4
fmt.Println(v.X)
}
結(jié)構(gòu)指針
結(jié)構(gòu)體字段可以通過結(jié)構(gòu)體指針來訪問沽甥。
通過指針間接的訪問是透明的
type Vertex struct{
X int
Y int
}
func main(){
v := Vertex{1,2}
p := &v
p.X = 1e9
fmt.Println(v)
}
結(jié)構(gòu)體符文
結(jié)構(gòu)體符文表示通過結(jié)構(gòu)體字段的值作為列表來新分配一個結(jié)構(gòu)體。
使用 Name: 語法可以僅列部分字段乏奥。(字段名的順序無關(guān)摆舟。)
特殊的前綴 & 返回一個指向結(jié)構(gòu)體的指針。
type Vertex struct {
X,Y int
}
var (
v1 = Vertex{1,2} //類型為 Vertex
v2 = Vertex{X:1} //Y:0 被省略
v3 = Vertex{ } //X:0 和 Y:0
p = &Vertex{1,2} //類型為 *Vertex
)
數(shù)組 (和C語言的數(shù)組概念類似)
類型 [n]T 是一個有 n 個類型為 T 的值的數(shù)組。
表達式
var a [10]int
定義變量 a 是一個有十個整數(shù)的數(shù)組恨诱。
數(shù)組的長度是其類型的一部分媳瞪,因此數(shù)組不能改變大小。這看起來是一個制約照宝,但是Go提供一個更加便利的方式來使用數(shù)組蛇受。
切片(slice)
一個 slice 會指向一個序列的值,并且包含了長度信息厕鹃。
[]T 是一個元素類型為 T 的切片(slice)兢仰。
len(s) 返回 slice s 的長度。
func main(){
s := []int{2,3,4,5,11,13}
fmt.Println("s ==",s)
for i:= 0 ; i < len(s) ; i++{
fmt.Printf("s[%d] == %d\n",i,s[i])
}
}
slice的切片
切片slice 可以包含任意的類型剂碴,包括另一個 slice
func main(){
//create a tic-tac-toe board
game := [][]string{
[]string{"_","_","_"},
[]string{"_","_","_"},
[]string{"_","_","_"},
}
game[0][0] = "X"
game[2][2] = "O"
game[2][0] = "X"
game[1][0] = "O"
game[0][2] = "X"
printBoard(game)
}
func printBoard(s [][]string){
for i:=0 ; i < len(s); i++{
fmt.Printf("%s\n",strings.Join(s[i]," ")) //TODO 不懂
}
}
對slice切片
slice可以重新切片把将,創(chuàng)建新的 slice 值指向相同的數(shù)組。
表達式:
s[lo:hi]
表示從 lo 到 hi-1 的slice元素忆矛,含前端察蹲,不包含后端。因此:
s[lo:lo]
是空的催训,而
s[lo:lo+1]
具備一個元素洽议。
func main(){
s := []int {2,3,5,7,11,13}
fmt.Println("s == ",s)
fmt.Println("s[1:4] ==",s[1:4])
//省略下標從0 開始
fmt.Println("s[:3] == ",s[:3])
//省略上標到 len(s) 結(jié)束
fmt.Println("s[4:] == ",s[4:])
}
構(gòu)造 slice
slice 由函數(shù) make 創(chuàng)建。這會分配一個全是零值的數(shù)組并且返回一個 slice 指向這個數(shù)組:
a := make([]int,5) // len(a) = 5
為了指定容量瞳腌,可傳遞第三個參數(shù)到make :
b := make([]int,0,5) //len(b) = 0 , cap(b) = 5
b = b[:cap(b)] //len(b) = 5 , cap(b) = 5
b = b[1:] //len(b) = 4 , cap(b) = 4
以下為示例代碼:
func main(){
a := make([]int,5)
printSlice("a",a)
b := make([]int,0,5)
printSlice("b",b)
c := b[:2]
printSlice("c",c)
d := c[2:5]
printSlice("d",d)
}
func printSlice(s string, x []int){
fmt.Printf("%s len=%d cap = %d %v\n",s,len(x),cap(x),x)
}
nil slice
slice 的零值是 nil
一個 nil 的 slice 的長度和容量是 0
var z []int
fmt.Println(z,len(z),cap(z))
if z == nil{
fmt.Println("nil!")
}
向slice添加元素
向 slice 的末尾添加元素是一種常見操作绞铃,因此 Go 提供了一個內(nèi)建函數(shù) append 。內(nèi)建函數(shù)的文檔對 append 有詳細介紹嫂侍。
func append(s []T, vs ...T) []T
append 的第一個參數(shù)是 s 是一個元素類型為 T 的 slice 儿捧,其余類型為 T 的值將會附加到該 slice 的末尾。
append 的結(jié)果是一個包含原 **slice** 所有元素加上新添加的元素 **slice**挑宠。
如果 s 的底層數(shù)組太小菲盾,而不能容納所有值的時候,會分配一個更大的數(shù)組各淀。返回 slice 會指向這個新分配的數(shù)組懒鉴。
func main(){
var a []int
printSlice("a",a)
a = append(a,0)
printSlice("a",a)
a = append(a,1)
printSlice("a",a)
a = append(a,2,3,4)
printSlice("a",a)
}
func printSlice(s string, x []int){
fmt.Printf("%s len=%d cap=%d %v\n", s , len(x) , cap(x) , x)
}
范圍(range)
for 循環(huán)的 range 格式可以對 slice 或者 map 進行迭代循環(huán)。
當使用 for 循環(huán)遍歷一個 slice 時候碎浇,每次迭代 range 將返回兩個值临谱。第一個是當前的下標(序號),第二個是該下標所對應(yīng)元素的一個拷貝奴璃。
var pow = []int{1,2,4,8,16,32,64,128}
func main(){
for i,v:= range pow{
fmt.Printf("2 ** %d = %d \n",i,v)
}
}
通過賦值給 _ 來忽略序號和值悉默。
如果只需要索引值,去掉 “苟穆,value” 的部分就可以了抄课。
func main(){
pow := make([] int,10)
for i := range pow{
pow[i] = 1 << uint(i)
}
for _,value := range pow{
fmt.Printf("%d\n",value)
}
}