Go語言概覽
Go語言是一個非常簡單的編程語言,簡潔二字貫穿整個Go語言。
讓我們通過幾個方面整體瞭解一下Go語言同時感受一下它的簡潔。
本文內容整理自互聯網。
版權歸原作者所有。
Go 語言的設計哲學是簡潔,在 Go 團隊的一次訪談中,Rob Pike 和 Ken Thompson 均有提到 Go 在誕生之初就選擇了一條與以往的編程語言所選擇的不同方法,僅嘗試提供編程過程中的必需品, 剔除掉紛繁複雜的語法糖和日漸增多的特性列表。
原始類型
原始的數值類型包括:
bool
uint8, uint16, uint32, uint64
int8, int16, int32, int64
float32, ,float64
complex64 ,complex128
別名類型包括:byte rune
還有三個特定類型(根據平臺架構有不同的大小):
uint
int
uintptr
高階的數據結構包括:
string
[42]byte
[]byte
struct{}{}
*int64
關鍵字
Go 語言本身只有 25 個關鍵字,涵蓋了包管理、常量與變量、流程控制、函數調用、數據結構 和併發控制六個方面的語言特性。
函數
func foo( argc int, argv []string) float64 { }
包管理
Go 語言以 package
爲代碼組織的最小單位,不允許產生 package
與 package
之間的循環依賴。 包管理涉及兩個關鍵字,package
負責聲明當前代碼所在的 package
的 Package Name
,import
則負責導入 當前 package
所依賴的包。導入的形式包括絕對路徑和相對路徑,還能夠在導入時候對 package
指定別名(alias
),甚至將別名指定爲下劃線,只導入所依賴包的 init
初始化函數。
package foo
import (
"go/types"
"golang.org/x/syscall"
"errors"
"xerrors"
"golang.org/x/errors"
_ "os/signal"
)
常量與變量
常量 const
與變量 var
是編程語言裏司空見慣的概念,Go 語言也不例外。 常量與變量的聲明允許類型推導,也允許明確指定值的類型。
const (
name = "val"
PI float64 = 3.1415926
)
var (
age = 18
)
變量除了使用 var
來進行聲明外,還可以在函數內部通過 :=
進行聲明。
下面是Go語言的其他一些關鍵字:
package import
const var
if else break continue
switch case default
for range
goto fallthrough
func return defer
type struct map interface
go chan select
內建
const (
true = 0 == 0
false = 0 != 0
iota = 0
)
var nil T
// 往切片末尾追加元素
func append(slice []T, elems ...T) []T
// 將 src 拷貝到 dst
func copy(dst, src []T) int
// 刪除
func delete(m map[T]U, key T)
func len(v T) int
func cap(v T) int
func make(t T, size ...IntegerT) T
func new(T) *T
func complex(r, i FloatT) ComplexT
func real(c ComplexT) FloatT
func imag(c ComplexT) FloatT
func close(c chan<- T)
func panic(v interface{})
func recover() interface{}
func print(args ...T)
func println(args ...T)
type error interface {
Error() string
}
Channel 與 Select
Channel 主要有兩種形式:
- 有緩存 Channel(buffered channel),使用
make(chan T, n)
創建 - 無緩存 Channel(unbuffered channel),使用
make(chan T)
創建
其中 T
爲 Channel 傳遞數據的類型,n
爲緩存的大小,這兩種 Channel 的讀寫操作都非常簡單:
// 創建有緩存
Channel ch := make(chan interface{}, 10)
// 創建無緩存
Channel ch := make(chan struct{})
// 發送
ch <- v
// 接受
v := <- ch
他們之間的本質區別在於其內存模型的差異,這種內存模型在 Channel 上體現爲:
- 有緩存 Channel:
ch <- v
發生在v <- ch
之前 - 有緩存 Channel:
close(ch)
發生在v <- ch && v == isZero(v)
之前 - 無緩存 Channel:
v <- ch
發生在ch <- v
之前 - 無緩存 Channel: 如果
len(ch) == C
,則從 Channel 中收到第 k 個值發生在 k+C 個值得發送完成之前
直觀上我們很好理解他們之間的差異: 對於有緩存 Channel 而言,內部有一個緩衝隊列,數據會優先進入緩衝隊列,而後才被消費, 即向通道發送數據 ch <- v
發生在從通道接受數據 v <- ch
之前; 對於無緩存 Channel 而言,內部沒有緩衝隊列,即向通道發送數據 ch <- v
一旦出現, 通道接受數據 v <- ch
會立即執行, 因此從通道接受數據 v <- ch
發生在向通道發送數據 ch <- v
之前。 我們隨後再根據實際實現來深入理解這一內存模型。
Go 語言還內建了 close()
函數來關閉一個 Channel:
close(ch)
但語言規範規定了一些要求:
- 關閉一個已關閉的 Channel 會導致 panic
- 向已經關閉的 Channel 發送數據會導致 panic
- 向已經關閉的 Channel 讀取數據不會導致 panic,但讀取的值爲 Channel 緩存數據的零值,可以通過接受語句第二個返回值來檢查 Channel 是否關閉:
v, ok := <- ch if !ok {
... // Channel 已經關閉
}
Select 語句伴隨 Channel 一起出現,常見的用法是:
select {
case ch <- v:
...
default: ...
}
或者:
select {
case v := <-ch:
...
default: ...
}
用於處理多個不同類型的 v
的發送與接收,並提供默認處理方式。
錯誤處理
Go 語言的錯誤處理被設計爲值類型,任何實現了 error
接口的類型均可以以 error
的類型返回:
type CustomErr struct {
err error
}
func (c CustomErr) Error() string {
return fmt.Sprintf("err: %v", c.err)
}
上面的 CustomErr
類型實現了 Error()
方法,於是可以以 error
類型返回給上層調用:
func foo() error {
return CustomErr{ /??/errors.New("this is an error") }
}
func main() {
err := foo()
if err != nil {
panic(err)
}
}