一、包
每個 Go 程序都是由包組成的。
程序運行的入口是包 main
。
這個程序使用并導入了包 fmt
和 math/rand
。
按照慣例,包名與導入路徑的最后一個目錄一致。例如,math/rand
包由 package rand
語句
開始。
注意:這個程序的運行環境是確定性的,因此 rand.Intn 每次都會返回相同的數字。 (為了得到
不同的隨機數,需要提供一個隨機數種子,參閱 rand.Seed 。)
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println("My favorite number is", rand.Intn(10))
}
這個代碼用圓括號組合了導入,這是“打包”導入語句。
同樣可以編寫多個導入語句,例如:
import "fmt"
import "math"
不過使用打包的導入語句是更好的形式。
package main
import (
"fmt"
"math"
)
func main() {
fmt.Printf("Now you have %g problems.", math.Sqrt(7))
}
在 Go 中,首字母大寫的名稱是被導出的。
在導入包之后,你只能訪問包所導出的名字,任何未導出的名字是不能被包外的代碼訪問的。
Foo 和 FOO 都是被導出的名稱。名稱 foo 是不會被導出的。
package main
import (
"fmt"
"math"
)
func main() {
fmt.Println(math.pi) // 應該是math.Pi
}
二、參數與變量
函數可以沒有參數或接受多個參數。
在這個例子中, 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
package main
import "fmt"
func add(x, y int) int {
return x + y
}
func main() {
fmt.Println(add(42, 13))
}
函數可以返回任意數量的返回值。
swap 函數返回了兩個字符串。
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)
}
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))
}
var
語句定義了一個變量的列表;跟函數的參數列表一樣,類型在后面。
就像在這個例子中看到的一樣, var
語句可以定義在包或函數級別。
package main
import "fmt"
var c, python, java bool
func main() {
var i int
fmt.Println(i, c, python, java)
}
變量定義可以包含初始值,每個變量對應一個。
如果初始化是使用表達式,則可以省略類型;變量從初始值中獲得類型。
package main
import "fmt"
var i, j int = 1, 2
func main() {
var c, python, java = true, false, "no!"
fmt.Println(i, j, c, python, java)
}
在函數中, :=
簡潔賦值語句在明確類型的地方,可以用于替代 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)
}
三、基本類型
Go 的基本類型有:
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位的系統上一般是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() {
const f = "%T(%v)\n"
fmt.Printf(f, ToBe, ToBe)
fmt.Printf(f, MaxInt, MaxInt)
fmt.Printf(f, z, z)
}
變量在定義時沒有明確的初始化時會賦值為 零值 。
零值是:
數值類型為 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)
}
表達式 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 或 int 的轉換看看會發生什么。
package main
import (
"fmt"
"math"
)
func main() {
var x, y int = 3, 4
var f float64 = math.Sqrt(float64(x*x + y*y))
var z uint = uint(f)
fmt.Println(x, y, z)
}
在定義一個變量卻并不顯式指定其類型時(使用 :=
語法或者 var =
表達式語法), 變量的類型由(等號)右側的值推導得出。
當右值定義了類型時,新變量的類型與其相同:
var i int
j := i // j 也是一個 int
但是當右邊包含了未指名類型的數字常量時,新的變量就可能是 int 、 float64 或 complex128。 這取決于常量的精度:
i := 42 // int
f := 3.142 // float64
g := 0.867 + 0.5i // complex128
常量的定義與變量類似,只不過使用 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)
}
數值常量是高精度的值 。
一個未指定類型的常量由上下文來決定其類型。
也嘗試一下輸出 needInt(Big)
吧。
(int
可以存放最大64位的整數,根據平臺不同有時會更少。)