Golang | 基礎 - 3. 變量

Golang | 基礎 - 3. 變量

3.1 變量

變量是幾乎全部編程語言中最基本的組成元素。從根本上說,變量至關因而對一塊數據存儲空間的命名,程序能夠經過定義一個變量來申請一塊數據存儲空間,以後能夠經過引用變量名來使用這塊存儲空間。程序員

Go語言中的變量使用方式與C語言接近,但具有更大的靈活性。golang

3.1.1 變量的聲明

Go語言的變量聲明方式與C和C++語言有明顯的不一樣。對於純粹的變量聲明,Go語言引入了關鍵字 var ,而類型信息放在變量名以後,示例以下:編程

var v1 int
var v2 string
var v3 [10]int               // 數組
var v4 []int                  // 數組切片
var v5 struct {
    f int
}
var v6 *int                  // 指針
var v7 map[string]int    // map,key爲string類型,value爲int類型
var v8 func(a int) int

變量聲明語句不須要使用分號做爲結束符。與C語言相比,Go語言摒棄了語句必須以分號做爲語句結束標記的習慣。數組

var關鍵字的另外一種用法是能夠將若干個須要聲明的變量放置在在一塊兒,省得程序員須要重複寫var關鍵字,以下所示:編程語言

var (
    v1 int
    v2 string
)

3.1.2 變量初始化

對於聲明變量時須要進行初始化的場景, var關鍵字能夠保留,但再也不是必要的元素,以下所示:ide

var v1 int = 10     // 正確的使用方式1
var v2 = 10         // 正確的使用方式2,編譯器能夠自動推導出v2的類型
v3 := 10             // 正確的使用方式3,編譯器能夠自動推導出v3的類型

以上三種用法的效果是徹底同樣的。與第一種用法相比,第三種用法須要輸入的字符數大大減小,是懶程序員和聰明程序員的最佳選擇。這裏Go語言也引入了另外一個C和C++中沒有的符號(冒號和等號的組合 := ),用於明確表達同時進行變量聲明和初始化的工做。函數

指定類型已再也不是必需的,Go編譯器能夠從初始化表達式的右值推導出該變量應該聲明爲哪一種類型,這讓Go語言看起來有點像動態類型語言,儘管Go語言其實是徹徹底底的強類型語言(靜態類型語言)。ui

固然,出如今 := 左側的變量不該該是已經被聲明過的,不然會致使編譯錯誤,好比下面這個寫法:編碼

var i int
i := 2
會致使相似以下的編譯錯誤:
no new variables on left side of :=

3.1.3 變量賦值

在Go語法中,變量初始化變量賦值是兩個不一樣的概念。下面爲聲明一個變量以後的賦值過程:指針

var v10 int
v10 = 123

Go語言的變量賦值與多數語言一致,但Go語言中提供了C/C++程序員期盼多年的多重賦值功能,好比下面這個交換ij變量的語句:

i, j = j, i

在不支持多重賦值的語言中,交互兩個變量的內容須要引入一箇中間變量:

t = i; 
i = j;
j = t;

多重賦值的特性在Go語言庫的實現中也被使用得至關充分,在介紹函數的多重返回值時,將對其進行更加深刻的介紹。總而言之,多重賦值功能讓Go語言與C/C++語言相比能夠很是明顯地減小代碼行數。

3.1.4 匿名變量

咱們在使用傳統的強類型語言編程時,常常會出現這種狀況,即在調用函數時爲了獲取一個值,卻由於該函數返回多個值而不得不定義一堆沒用的變量。在Go中這種狀況能夠經過結合使用多重返回匿名變量來避免這種醜陋的寫法,讓代碼看起來更加優雅。

假設 GetName() 函數的定義以下,它返回3個值,分別爲firstName, lastNamenickName

func GetName() (firstName, lastName, nickName string) {
    return "May", "Chan", "Chibi Maruko"
}

若只想得到 nickName ,則函數調用語句能夠用以下方式編寫:

_, _, nickName := GetName()

這種用法可讓代碼很是清晰,基本上屏蔽掉了可能混淆代碼閱讀者視線的內容,從而大幅下降溝通的複雜度和代碼維護的難度。

3.2 常量

在Go語言中,常量是指編譯期間就已知且不可改變的值。常量能夠是數值類型(包括整型、
浮點型和複數類型)、布爾類型、字符串類型等。

3.2.1 字面常量

所謂字面常量(literal),是指程序中硬編碼的常量,如:

-12
3.14159265358979323846      // 浮點類型的常量
3.2+12i                              // 複數類型的常量
true                                    // 布爾類型的常量
"foo"                                   // 字符串常量

在其餘語言中,常量一般有特定的類型,好比 -12 在C語言中會認爲是一個 int 類型的常量。若是要指定一個值爲 -12long 類型常量,須要寫成 -12l ,這有點違反人們的直觀感受。Go語言的字面常量更接近咱們天然語言中的常量概念,它是無類型的。只要這個常量在相應類型的值域範圍內,就能夠做爲該類型的常量,好比上面的常量 -12 ,它能夠賦值給 intuintint32int64float32float64complex64complex128 等類型的變量。

3.2.2 常量定義

經過 const 關鍵字,你能夠給字面常量指定一個友好的名字:

const Pi float64 = 3.14159265358979323846
const zero = 0.0                  // 無類型浮點常量
const (
    size int64 = 1024
    eof = -1                        // 無類型整型常量
)
const u, v float32 = 0, 3       // u = 0.0, v = 3.0,常量的多重賦值
const a, b, c = 3, 4, "foo"     // a = 3, b = 4, c = "foo", 無類型整型和字符串常量

Go的常量定義能夠限定常量類型,但不是必需的。若是定義常量時沒有指定類型,那麼它與字面常量同樣,是無類型常量。

常量定義的右值也能夠是一個在編譯期運算的常量表達式,好比

const mask = 1 << 3

因爲常量的賦值是一個編譯期行爲,因此右值不能出現任何須要運行期才能得出結果的表達式,好比試圖以以下方式定義常量就會致使編譯錯誤:

const Home = os.GetEnv("HOME")

緣由很簡單, os.GetEnv() 只有在運行期才能知道返回結果,在編譯期並不能肯定,因此
沒法做爲常量定義的右值。

3.2.3 預約義常量

Go語言預約義了這些常量: truefalseiota

iota 比較特殊,能夠被認爲是一個可被編譯器修改的常量,在每個 const 關鍵字出現時被重置爲0,而後在下一個 const 出現以前,每出現一次 iota ,其所表明的數字會自動增1

從如下的例子能夠基本理解 iota 的用法:

const (               // iota被重設爲0
    c0 = iota        // c0 == 0
    c1 = iota        // c1 == 1
    c2 = iota        // c2 == 2
)

const (
    a = 1 << iota        // a == 1 (iota在每一個const開頭被重設爲0)
    b = 1 << iota        // b == 2
    c = 1 << iota        // c == 4
)

const (
    u = iota * 42             // u == 0
    v float64 = iota * 42   // v == 42.0
    w = iota * 42            // w == 84
)
const x = iota        // x == 0 (由於iota又被重設爲0了)
const y = iota        // y == 0 (同上)

若是兩個 const 的賦值語句的表達式是同樣的,那麼能夠省略後一個賦值表達式。所以,上面的前兩個 const 語句可簡寫爲:

const (                  // iota被重設爲0
    c0 = iota           // c0 == 0
    c1                    // c1 == 1
    c2                    // c2 == 2
)

const (
    a = 1 <<iota     // a == 1 (iota在每一個const開頭被重設爲0)
    b                    // b == 2
    c                    // c == 4
)

3.2.3.1 iota

iotagolang 語言的常量計數器,只能在常量的表達式中使用。

使用 iota 能簡化定義,在定義枚舉時頗有用。

舉例:

3.2.3.1.1 iota只能在常量的表達式中使用
fmt.Println(iota) 
編譯錯誤: undefined: iota
3.2.3.1.2 每次 const 出現時,都會讓 iota 初始化爲0
const a = iota // a=0
const (
  b = iota     //b=0
  c             //c=1
)
3.2.3.1.3 自定義類型

自增加常量常常包含一個自定義枚舉類型,容許你依靠編譯器完成自增設置。

type Stereotype intconst (
    TypicalNoob Stereotype = iota // 0
    TypicalHipster                      // 1
    TypicalUnixWizard                 // 2
    TypicalStartupFounder            // 3
)
3.2.3.1.4 可跳過的值

設想你在處理消費者的音頻輸出。音頻可能不管什麼都沒有任何輸出,或者它多是單聲道,立體聲,或是環繞立體聲的。
這可能有些潛在的邏輯定義沒有任何輸出爲 0,單聲道爲 1,立體聲爲 2,值是由通道的數量提供。
因此你給 Dolby 5.1 環繞立體聲什麼值。
一方面,它有6個通道輸出,可是另外一方面,僅僅 5 個通道是全帶寬通道(所以 5.1 稱號 - 其中 .1 表示的是低頻效果通道)。
無論怎樣,咱們不想簡單的增長到 3。
咱們可使用下劃線跳過不想要的值。

type AudioOutput intconst (
    OutMute AudioOutput = iota  // 0
    OutMono                            // 1
    OutStereo                           // 2
    _
    _
    OutSurround                         // 5
)
3.2.3.1.5 位掩碼錶達式
type Allergen int
const (
    IgEggs Allergen = 1 << iota   // 1 << 0 which is 00000001
    IgChocolate                         // 1 << 1 which is 00000010
    IgNuts                                // 1 << 2 which is 00000100
    IgStrawberries                      // 1 << 3 which is 00001000
    IgShellfish                           // 1 << 4 which is 00010000
)

這個工做是由於當你在一個 const 組中僅僅有一個標示符在一行的時候,它將使用增加的 iota 取得前面的表達式而且再運用它。
在 Go 語言的 spec 中, 這就是所謂的隱性重複最後一個非空的表達式列表。若是你對雞蛋,巧克力和海鮮過敏,把這些 bits 翻轉到 「on」 的位置(從左到右映射 bits)。而後你將獲得一個 bit 值 00010011,它對應十進制的 19
fmt.Println(IgEggs | IgChocolate | IgShellfish)
// output:
// 19

3.2.3.1.6 定義數量級
type ByteSize float64

const (
    _           = iota                   // ignore first value by assigning to blank identifier
    KB ByteSize = 1 << (10 * iota) // 1 << (10*1)
    MB                                   // 1 << (10*2)
    GB                                   // 1 << (10*3)
    TB                                   // 1 << (10*4)
    PB                                   // 1 << (10*5)
    EB                                   // 1 << (10*6)
    ZB                                   // 1 << (10*7)
    YB                                   // 1 << (10*8)
)
3.2.3.1.7 中間插隊
const (
    i = iota
    j = 3.14
    k = iota
    l
)
那麼打印出來的結果是 i=0,j=3.14,k=2,l=3

3.2.4 枚舉

枚舉指一系列相關的常量,好比下面關於一個星期中天天的定義。經過上一節的例子,咱們看到能夠用在 const 後跟一對圓括號的方式定義一組常量,這種定義法在Go語言中一般用於定義枚舉值。Go語言並不支持衆多其餘語言明確支持的 enum 關鍵字。

下面是一個常規的枚舉表示法,其中定義了一系列整型常量:

const (
    Sunday = iota
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
    numberOfDays   // 這個常量沒有導出
)

同Go語言的其餘符號(symbol)同樣,以大寫字母開頭的常量在包外可見。
以上例子中 numberOfDays 爲包內私有,其餘符號則可被其餘包訪問。

相關文章
相關標籤/搜索