0. What’s golang?
- Google公司傾力打造
- 爲現代系統設計(多核, 並行)
- 天生適合網絡編程,後端
- 至精至簡,依賴關係簡單
- 跨平臺
- 靜態語言,穩定而易於管理大型項目
1. Go語言初步
1.1 包(package)
每個 Go 程序都是由包構成的。
程序從 main 包開始運行。
本程序通過導入路徑 “fmt” 和 “math/rand” 來使用這兩個包。
按照約定,包名與導入路徑的最後一個元素一致。例如,”math/rand” 包中的源碼均以 package rand 語句開始。
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println("My favorite number is", rand.Intn(10))
}
輸出:
My favorite number is 1
1.2 導入
此代碼用圓括號組合了導入,這是“分組”形式的導入語句。
當然你也可以編寫多個導入語句,例如:
import "fmt"
import "math"
不過使用分組導入語句是更好的形式。
1.3 導出名
在 Go 中,如果一個名字以大寫字母開頭,那麼它就是已導出的。 例如, Pizza 就是個已導出名, Pi 也同樣,它導出自 math 包。
pizza 和 pi 並未以大寫字母開頭,所以它們是未導出的。
在導入一個包時,你只能引用其中已導出的名字。任何“未導出”的名字在該包外均無法訪問。
1.4 函數
函數可以沒有參數或接受多個參數。
在本例中, add 接受兩個 int 類型的參數。
注意類型在變量名 之後 。
package main
import "fmt"
func add(x int, y int) int {
return x + y
}
func main() {
fmt.Println(add(42, 13))
}
花括號不能另起行!!!
當連續兩個或多個函數的已命名形參類型相同時,除最後一個類型以外,其它都可以省略。x int, y int
可以被縮寫爲
x, y int
1.5 函數多值返回
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
1.6 命名返回值
Go 的返回值可被命名,它們會被視作定義在函數頂部的變量。
返回值的名稱應當具有一定的意義,它可以作爲文檔使用。
沒有參數的 return 語句返回已命名的返回值。也就是直接
返回。
直接返回語句應當僅用在下面這樣的短函數中。在長的函數中它們會影響代碼的可讀性。
package main
import "fmt"
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
func main() {
fmt.Println(split(17))
}
1.7 變量
var 語句用於聲明一個變量列表,跟函數的參數列表一樣,類型在最後。
就像在這個例子中看到的一樣, var 語句可以出現在包或函數級別。
package main
import "fmt"
var c, python, java bool
func main() {
var i int
fmt.Println(i, c, python, java)
}
輸出
0 false false fasle
變量可以做如下初始化:
var i, j int = 1, 2
1.8 短變量聲明
在函數中,簡潔賦值語句 := 可在類型明確的地方代替 var 聲明。
函數外的每個語句都必須以關鍵字開始( var 、 func 等等), 因此 := 結構不能在函數外使用。
package main
import "fmt"
func main() {
var i, j int = 1, 2
k := 3
c, python, java := true, false, "no!"
fmt.Println(i, j, k, c, python, java)
}
1 2 3 true false no!
1.9 基本類型
bool
string
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptrbyte // uint8 的別名
rune // int32 的別名
// 表示一個 Unicode 碼點float32 float64
complex64 complex128
同導入語句一樣,變量聲明也可以“分組”成一個語法塊。
int 、 uint 和 uintptr 在 32 位系統上通常爲 32 位寬,在 64 位系統上則爲 64 位寬。 當你需要一個整數值時應使用 int 類型,除非你有特殊的理由使用固定大小或無符號的整數類型。
package main
import (
"fmt"
"math/cmplx"
)
var (
ToBe bool = false
MaxInt uint64 = 1<<64 - 1
z complex128 = cmplx.Sqrt(-5 + 12i)
)
func main() {
fmt.Printf("Type: %T Value: %v\n", ToBe, ToBe)
fmt.Printf("Type: %T Value: %v\n", MaxInt, MaxInt)
fmt.Printf("Type: %T Value: %v\n", z, z)
}
Type: bool Value: false
Type: uint64 Value: 18446744073709551615
Type: complex128 Value: (2+3i)
1.10 零值
沒有明確初始值的變量聲明會被賦予它們的 零值 。
零值是:
數值類型爲 0 ,
布爾類型爲 false ,
字符串爲 “” (空字符串)。
1.11 類型轉換
表達式 T(v) 將值 v 轉換爲類型 T 。
一些關於數值的轉換:
var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
或者,更加簡單的形式:
i := 42
f := float64(i)
u := uint(f)
與 C 不同的是,Go 在不同類型的項之間賦值時需要顯式轉換。 試着移除例子中 float64 或 uint 的轉換看看會發生什麼。
1.12 類型推導
在聲明一個變量而不指定其類型時(即使用不帶類型的 := 語法 或 var = 表達式語法), 變量的類型由右值推導得出。
當右值聲明瞭類型時,新變量的類型與其相同:
var i int
j := i // j 也是一個 int
不過當右邊包含未指明類型的數值常量時,新變量的類型就可能是 int 、 float64 或 complex128 了,這取決於常量的精度:
i := 42 // int
f := 3.142 // float64
g := 0.867 + 0.5i // complex128
嘗試修改示例代碼中 v 的初始值,並觀察它是如何影響類型的。
1.13 常量
常量的聲明與變量類似,只不過是使用 const 關鍵字。
常量可以是字符、字符串、布爾值或數值。
常量不能用 := 語法聲明。
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)
}
Happy 3.14 Day
Go rules? true
1.14 數值常量
數值常量是高精度的 值 。
一個未指定類型的常量由上下文來決定其類型。
再嘗試一下輸出 needInt(Big) 吧。
( int 類型最大可以存儲一個 64 位的整數,有時會更小。)
(int 可以存放最大64位的整數,根據平臺不同有時會更少。)
package main
import "fmt"
const (
// Create a huge number by shifting a 1 bit left 100 places.
// In other words, the binary number that is 1 followed by 100 zeroes.
Big = 1 << 100
// Shift it right again 99 places, so we end up with 1<<1, or 2.
Small = Big >> 99
)
func needInt(x int) int { return x*10 + 1 }
func needFloat(x float64) float64 {
return x * 0.1
}
func main() {
fmt.Println(needInt(Small))
fmt.Println(needFloat(Small))
fmt.Println(needFloat(Big))
}