Go語言概覽

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 爲代碼組織的最小單位,不允許產生 packagepackage 之間的循環依賴。 包管理涉及兩個關鍵字,package 負責聲明當前代碼所在的 packagePackage Nameimport 則負責導入 當前 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 主要有兩種形式:

  1. 有緩存 Channel(buffered channel),使用 make(chan T, n) 創建
  2. 無緩存 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) 
  } 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章