雲計算之go語言——基礎語法(上)

1 Go 語言教程


人無完人,同樣,語言也沒有完美無缺的,使用一款新的語言,接受它的優點的同時,也要了解與避免它的缺點。
1. 概念
    Go 是一個開源的編程語言,它能讓構造簡單、可靠且高效的軟件變得容易。
2. 特點與特性
    1) 特點
        簡潔,快速,安全
        並行,開源
        內存管理,數組安全,編譯迅速
    2) 特性
        自動垃圾回收
        更豐富的內置類型
        函數多返回值
        錯誤處理
        匿名函數和閉包
        類型和接口
        併發編程
        反射
        語言交互性
3. 用途
    Go 語言被設計成一門應用於搭載 Web 服務器,存儲集羣或類似用途的巨型中央服務器的系統編程語言。
    對於高性能分佈式系統領域而言,Go 語言無疑比大多數其它語言有着更高的開發效率。它提供了海量並行的支持,這對於遊戲服務端的開發而言是再好不過了。
4. hello.go
    pachage main
    import "fmt"
    func main(){
        fmt.Println("Hello, World!")
    }
    運行方式
    1) go run hello.go
    2) go build hello.go ; ./hello
5. 和其他語言比較
    比C++多了GC,C++老是內存泄漏
    比java簡潔
    比python更快
    但是歸根結底,對一般程序員來說,語言差別不多,垃圾代碼的鍋還得是程序員自己背,怨不得語言。
6. go編程哲學
    小而精: 不要複雜化,維持語言特性的簡潔
    1) 面向接口編程
    2)使用組合的編程
    3)正交性:語言設計的正交性,保證語言的穩定性和簡單性
    4)少即是多:有且僅有一種方法把事情做好做對
    5)併發語言層面支持:併發更好利用多核,有更強的表現力來模擬真實世界
    6)開放性:開源,語言的實現對程序員不是個黑盒子,任何想了解語言實現的人可以參與進來
7. go語言的缺點
    1)左花括號不可以另起一行
    2)gc編譯器給行尾加分號
    3)功能少,強調編譯速度:一些檢查,約束,覈對性工作等常規錯誤,需要使用者自己寫功能處理
    4)錯誤處理機制不完善
    5)GC垃圾回收器啓動後會導致短暫的服務中斷
    6)禁止未使用變量和多餘import:在調試項目的過程中是一個很大的坑
    7)創建對象的方式太多:不同需求使用不同方式
    8)接口不夠優雅:放進去的對象取出後無類型
    9)編譯生成的可執行文件大:一個簡簡單單的helloworld,編譯後有2M大小
    10)不支持動態庫加載類庫:動態庫無需編譯,可以節省很大容量,動態庫可以在運行時加載卸載

2 Go 語言環境安裝

 

1. Go 語言支持以下系統:
    Linux
    Mac OS X
    Windows
2. 安裝包地址: https://golang.google.cn/dl/
3. Linux/Mac OS X安裝方式
    tar -C /usr/local -xzf go1.10.3.linux-amd64.tar.gz
    export PATH=$PATH:/usr/local/go/bin
4. Windows 系統安裝
    默認情況下 .msi 文件會安裝在 c:\Go 目錄下。你可以將 c:\Go\bin 目錄添加到 Path 環境變量中。添加後你需要重啓命令窗口才能生效。
5. 運行測試
    go\demos>C:\Go\bin\go run hello.go
        Hello, World!
    go\demos>C:\Go\bin\go build hello.go
    go\demos>hello
        Hello, World!
6. pycharm編譯器go語言語法高亮
    File -> Settings -> Plugins -> 搜 go language -> install -> 重啓
    如果沒有搜索到go language
    https://plugins.jetbrains.com/plugin/5047-go-language-golang-org-support-plugin/versions 下載插件
    解壓插件包
        Go-0.13.1924.zip -> lib -> intellij-go-*.jar -> META-INF\plugin.xml -> 修改 <idea-version since-build=" AAA.BBBB" until-build="AAA .*"/> (你的idea版本是  AAA.BBBB.CCC,自己找readme),替換好後,從新打zip包。

 

3 Go 語言結構

 

1. 組成部分
    包聲明
    引入包
    函數
    變量
    語句 & 表達式
    註釋
2. 代碼示例
    package main

    import "fmt"

    func main() {
       /* 這是我的第一個簡單的程序 */
       fmt.Println("Hello, World!")
    }
    ============================================
    package main : 定義包名,非註釋的第一行指明這個文件屬於哪個包。表示一個可獨立執行的程序,每個 Go 應用程序都包含一個名爲 main 的包。此處和文件名無關。
    import "fmt" : 告訴GC要使用fmt包[內置,fmt 包實現了格式化 IO(輸入/輸出)的函數]
    func main(){ : 是程序開始執行的函數。main 函數是每一個可執行程序所必須包含的,一般來說都是在啓動後第一個執行的函數(如果有 init() 函數則會先執行該函數)。
    /*...*/      : 註釋,在程序執行時將被忽略。多行註釋一般用於包的文檔描述或註釋成塊的代碼片段。
    fmt.Print()  : 將字符串輸出到控制檯,並在最後自動增加換行字符 \n。
    標識符       : 大寫字母開頭,可以被 外部包代碼使用,導出;小寫字母開頭,在整個包內部可用。

 

4 Go 語言基礎語法

 

1. Go 標記
    Go 程序可以由多個標記組成,可以是關鍵字,標識符,常量,字符串,符號。
2. 行分隔符
    在 Go 程序中,一行代表一個語句結束。每個語句不需要像 C 家族中的其它語言一樣以分號 ; 結尾,因爲這些工作都將由 Go 編譯器自動完成。
3. 註釋
    註釋不會被編譯,每一個包應該有相關注釋。
    單行註釋是最常見的註釋形式,你可以在任何地方使用以 // 開頭的單行註釋。多行註釋也叫塊註釋,均已以 /* 開頭,並以 */ 結尾。
4. 標識符
    標識符用來命名變量、類型等程序實體。一個標識符實際上就是一個或是多個字母(A~Z和a~z)數字(0~9)、下劃線_組成的序列,但是第一個字符必須是字母或下劃線而不能是數字。
5. 字符串連接
    Go 語言的字符串可以通過 + 實現
6. 關鍵字
    a.  25 個關鍵字或保留字
        break      default        func   interface  select
        case       defer      go     map            struct
        chan       else       goto   package        switch
        const      fallthrough    if     range      type
        continue   for            import return     var
    b. 36 個預定義標識符
        append bool   byte   cap            close  complex        complex64  complex128 uint16
        copy   false  float32    float64        imag   int            int8       int16      uint32
        int32  int64  iota   len            make   new            nil            panic      uint64
        print  println    real   recover        string true       uint       uint8      uintptr
7. Go 語言的空格
    Go 語言中變量的聲明必須使用空格隔開。例如:var age int;
    在變量與運算符間加入空格,程序看起來更加美觀。例如:c = a + b;

 

5 Go 語言數據類型

 

1. 描述
    在 Go 編程語言中,數據類型用於聲明函數和變量。
    數據類型的出現是爲了把數據分成所需內存大小不同的數據,編程的時候需要用大數據的時候才需要申請大內存,就可以充分利用內存。
2. 數據類型
    a. 布爾型
        布爾型的值只可以是常量 true 或者 false。一個簡單的例子:var b bool = true。
    b. 數字類型
        整型 int 和浮點型 float32、float64,Go 語言支持整型和浮點型數字,並且支持複數,其中位的運算採用補碼。
        i. 整型
            uint8:無符號 8 位整型 (0 到 255)
            int8:有符號 8 位整型 (-128 到 127)
            uint16:無符號 16 位整型 (0 到 65535)
            int16:有符號 16 位整型 (-32768 到 32767)
            uint32:無符號 32 位整型 (0 到 4294967295)
            int32:有符號 32 位整型 (-2147483648 到 2147483647)
            uint64:無符號 64 位整型 (0 到 18446744073709551615)
            int64:有符號 64 位整型 (-9223372036854775808 到 9223372036854775807)
    c. 字符串類型
        字符串就是一串固定長度的字符連接起來的字符序列。Go 的字符串是由單個字節連接起來的。Go 語言的字符串的字節使用 UTF-8 編碼標識 Unicode 文本。
    d. 派生類型
        指針類型(Pointer)
        數組類型
        結構化類型(struct)
        Channel 類型
        函數類型
        切片類型
        接口類型(interface)
        Map 類型

 

6 Go 語言變量

 

1. 概念
    Go 語言變量名由字母、數字、下劃線組成,其中首個字符不能爲數字。
2. 聲明方式
    var identifier type
    var identifier1, identifier2 type
3. 示例
    vars01.go
        package main
        import "fmt"
        func main(){
            var a string = "Runoob"
            fmt.Println(a)
            var b,c int = 1,2
            fmt.Println(b,c)
        }
    go run vars01.go
        Runoob
        1 2
4. 類型
    第一種,指定變量類型,如果沒有初始化,則變量默認爲零值。
        vars02.go
            package main
            import "fmt"
            func main(){
                var a = "Runoob"
                fmt.Println(a)
                var b int
                fmt.Println(b)
                var c bool
                fmt.Println(c)
            }
        go run vars02.go
            Runoob
            0
            false
        vars03.go
            package main

            import "fmt"

            func main(){
                var a int
                var b float64
                var c string
                var d bool
                fmt.Printf("%v %v %q %v\n",a,b,c,d)
            }
        go run vars03.go
            0 0 "" false
    第二種,根據值自行判定變量類型。
        vars04.go
            package main

            import "fmt"

            func main(){
                var a = true
                fmt.Println(a)
            }
        go run vars04.go
    第三種,省略 var, 注意 := 左側如果沒有聲明新的變量,就產生編譯錯誤,格式:
        v_name := value
        vars05.go
            package main

            import "fmt"

            func main(){
                f := "Runoob"
                fmt.Println(f)
            }
        go run vars05.go
            Runoob
    多變量聲明
        vars06.go
            package main

            import "fmt"

            var x,y int
            // 這種因式分解關鍵字一般用於全局變量
            var (
                a int
                b bool
            )

            var c,d int = 1, 2
            var e,f = 123, "hello"

            func main(){
                // 這種 := 聲明模式一般用於局部變量
                g, h := 111 , "world"
                fmt.Println(x,y,a,b,c,d,e,f,g,h)
            }
        注意: 字符串要使用雙引號
        go run vars06.go
            0 0 0 false 1 2 123 hello 111 world
5. 值類型和引用類型
    所有像 int、float、bool 和 string 這些基本類型都屬於值類型,使用這些類型的變量直接指向存在內存中的值
    當使用等號 = 將一個變量的值賦值給另一個變量時,如:j = i,實際上是在內存中將 i 的值進行了拷貝
    你可以通過 &i 來獲取變量 i 的內存地址,例如:0xf840000040(每次的地址都可能不一樣)。值類型的變量的值存儲在棧中。
    內存地址會根據機器的不同而有所不同,甚至相同的程序在不同的機器上執行後也會有不同的內存地址。因爲每臺機器可能有不同的存儲器佈局,並且位置分配也可能不同。
    更復雜的數據通常會需要使用多個數據,這些數據一般使用引用類型保存。
    一個引用類型的變量 r1 存儲的是 r1 的值所在的內存地址(數字),或內存地址中第一個字所在的位置。
    這個內存地址爲稱之爲指針,這個指針實際上也被存在另外的某一個字中。
    同一個引用類型的指針指向的多個字可以是在連續的內存地址中(內存佈局是連續的),這也是計算效率最高的一種存儲形式;也可以將這些字分散存放在內存中,每個字都指示了下一個字所在的內存地址。
    當使用賦值語句 r2 = r1 時,只有引用(地址)被複制。
    如果 r1 的值被改變了,那麼這個值的所有引用都會指向被修改後的內容。
6. 簡短形式,使用 := 賦值操作符
    a. 注意:
        如果在相同的代碼塊中,我們不可以再次對於相同名稱的變量使用初始化聲明,例如:a := 20 就是不被允許的,編譯器會提示錯誤 no new variables on left side of :=,但是 a = 20 是可以的,因爲這是給相同的變量賦予一個新的值。
        如果你在定義變量 a 之前使用它,則會得到編譯錯誤 undefined: a。
        如果你聲明瞭一個局部變量卻沒有在相同的代碼塊中使用它,同樣會得到編譯錯誤
        但是全局變量是允許聲明但不使用。 同一類型的多個變量可以聲明在同一行
        如果你想要交換兩個變量的值,則可以簡單地使用 a, b = b, a,兩個變量的類型必須是相同。
        空白標識符 _ 也被用於拋棄值,如值 5 在:_, b = 5, 7 中被拋棄。
        _ 實際上是一個只寫變量,你不能得到它的值。這樣做是因爲 Go 語言中你必須使用所有被聲明的變量,但有時你並不需要使用從一個函數得到的所有返回值。
        並行賦值也被用於當一個函數返回多個返回值時,比如這裏的 val 和錯誤 err 是通過調用 Func1 函數同時得到:val, err = Func1(var1)。
    b. 空白標識符應用
        vars07.go
            package main

            import "fmt"

            func main(){
                _,num,str := numbers() // 只獲取函數返回值的後兩個
                fmt.Println(num,str)
            }

            // 一個可以返回多個值的函數
            func numbers()(int,int,string){
                a, b, c := 1,2,"hello"
                return a, b ,c
            }
        go run vars07.go
            2 hello

 

7 Go 語言常量

 

1. 概念
    常量是一個簡單值的標識符,在程序運行時,不會被修改的量。
    常量中的數據類型只可以是布爾型、數字型(整數型、浮點型和複數)和字符串型。
2. 聲明
    顯式類型定義: const b string = "abc"
    隱式類型定義: const b = "abc"
3. 示例
    consts01.go
        package main

        import "fmt"

        func main(){
            const LENGTH int = 10
            const WIDTH int = 5
            var area int
            const a,b,c = 1, false, "str"
            area = LENGTH * WIDTH
            fmt.Printf("面積爲: %d" , area)
            println()
            println(a,b,c)
        }
    go run consts01.go
        面積爲: 50
        1 false str
4. 常量還可以用作枚舉
    const (
        Unkonwn = 0
        Female = 1
        Male = 2
    )
5. 常量可以用len(), cap(), unsafe.Sizeof()函數計算表達式的值。常量表達式中,函數必須是內置函數,否則編譯不過
    consts02.go
        package main

        import "unsafe"

        const (
            a = "abc"
            b = len(a)
            c  = unsafe.Sizeof(a)
        )

        func main(){
            println(a,b,c)
        }
    go run consts02.go
        abc 3 16
6. iota
    iota,特殊常量,可以認爲是一個可以被編譯器修改的常量。
    iota 在 const關鍵字出現時將被重置爲 0(const 內部的第一行之前),const 中每新增一行常量聲明將使 iota 計數一次(iota 可理解爲 const 語句塊中的行索引)。
    iota 可以被用作枚舉值:
        const (
            a = iota
            b = iota
            c = iota
        )
    第一個 iota 等於 0,每當 iota 在新的一行被使用時,它的值都會自動加 1;所以 a=0, b=1, c=2 可以簡寫爲如下形式:
        const (
            a = iota
            b
            c
        )
    用法 consts03.go
        package main

        import "fmt"

        func main()  {
            const (
                a = iota
                b
                c
                d = "ha"
                e
                f = 100
                g
                h = iota
                i
            )
            fmt.Println(a,b,c,d,e,f,g,h,i)
        }
    go run consts03.go
        0 1 2 ha ha 100 100 7 8
    consts04.go
        package main

        import (
            "fmt"
        )

        const (
            i = 1 << iota
            j = 3 << iota
            k
            l
        )

        func main()  {
            fmt.Println("i=",i)
            fmt.Println("j=",j)
            fmt.Println("k=",k)
            fmt.Println("l=",l)
        }
    go run consts04.go
        i= 1
        j= 6
        k= 12
        l= 24
    i=1:左移 0 位,不變仍爲 1;
    j=3:左移 1 位,變爲二進制 110, 即 6;
    k=3:左移 2 位,變爲二進制 1100, 即 12;
    l=3:左移 3 位,變爲二進制 11000,即 24。

 

8 Go 語言運算符

 

1. 概念
    運算符用於在程序運行時執行數學或邏輯運算。
2. 分類
    a. 算術運算符
        + , - , * , / , % , ++ , --
        opts01.go
            package main

            import (
                "fmt"
            )

            func main()  {

                var a int = 21
                var b int = 10
                var c int

                c = a + b
                fmt.Printf("第一行: - c 的值爲 %d\n", c)
                c = a - b
                fmt.Printf("第二行: - c 的值爲 %d\n", c)
                c = a * b
                fmt.Printf("第三行: - c 的值爲 %d\n", c)
                c = a / b
                fmt.Printf("第四行: - c 的值爲 %d\n", c)
                c = a % b
                fmt.Printf("第五行: - c 的值爲 %d\n", c)
                a++
                fmt.Printf("第六行: - a 的值爲 %d\n", a)
                a=21
                a--
                fmt.Printf("第七行: - a 的值爲 %d\n", a)
            }
    b. 關係運算符
        ==, !=, >, <, >=, <=
        opts02.go
            package main

            import "fmt"

            func main()  {
               var a int = 21
               var b int = 10

               if( a == b ) {
                  fmt.Printf("第一行 - a 等於 b\n" )
               } else {
                  fmt.Printf("第一行 - a 不等於 b\n" )
               }
               if ( a < b ) {
                  fmt.Printf("第二行 - a 小於 b\n" )
               } else {
                  fmt.Printf("第二行 - a 不小於 b\n" )
               }

               if ( a > b ) {
                  fmt.Printf("第三行 - a 大於 b\n" )
               } else {
                  fmt.Printf("第三行 - a 不大於 b\n" )
               }
               /* Lets change value of a and b */
               a = 5
               b = 20
               if ( a <= b ) {
                  fmt.Printf("第四行 - a 小於等於 b\n" )
               }
               if ( b >= a ) {
                  fmt.Printf("第五行 - b 大於等於 a\n" )
               }
            }

    c. 邏輯運算符
        &&, ||, !
        opts03.go
            package main

            import "fmt"

            func main() {
               var a bool = true
               var b bool = false
               if ( a && b ) {
                  fmt.Printf("第一行 - 條件爲 true\n" )
               }
               if ( a || b ) {
                  fmt.Printf("第二行 - 條件爲 true\n" )
               }
               /* 修改 a 和 b 的值 */
               a = false
               b = true
               if ( a && b ) {
                  fmt.Printf("第三行 - 條件爲 true\n" )
               } else {
                  fmt.Printf("第三行 - 條件爲 false\n" )
               }
               if ( !(a && b) ) {
                  fmt.Printf("第四行 - 條件爲 true\n" )
               }
            }
    d. 位運算符
        &,|,^:用的少,此處不舉例子
    e. 賦值運算符
        =, +=, -=, *=, /=, %=, <<=, >>=, &=, ^=, !=
        opts04.go
            package main

            import "fmt"

            func main() {
               var a int = 21
               var c int

               c =  a
               fmt.Printf("第 1 行 - =  運算符實例,c 值爲 = %d\n", c )

               c +=  a
               fmt.Printf("第 2 行 - += 運算符實例,c 值爲 = %d\n", c )

               c -=  a
               fmt.Printf("第 3 行 - -= 運算符實例,c 值爲 = %d\n", c )

               c *=  a
               fmt.Printf("第 4 行 - *= 運算符實例,c 值爲 = %d\n", c )

               c /=  a
               fmt.Printf("第 5 行 - /= 運算符實例,c 值爲 = %d\n", c )

               c  = 200;

               c <<=  2
               fmt.Printf("第 6行  - <<= 運算符實例,c 值爲 = %d\n", c )

               c >>=  2
               fmt.Printf("第 7 行 - >>= 運算符實例,c 值爲 = %d\n", c )

               c &=  2
               fmt.Printf("第 8 行 - &= 運算符實例,c 值爲 = %d\n", c )

               c ^=  2
               fmt.Printf("第 9 行 - ^= 運算符實例,c 值爲 = %d\n", c )

               c |=  2
               fmt.Printf("第 10 行 - |= 運算符實例,c 值爲 = %d\n", c )

            }
    f. 其他運算符
        &: 返回變量存儲地址,&a; 將給出變量的實際地址。
        *: 指針變量。*a; 是一個指針變量
        opts05
            package main

            import "fmt"

            func main() {
               var a int = 4
               var b int32
               var c float32
               var ptr *int

               /* 運算符實例 */
               fmt.Printf("第 1 行 - a 變量類型爲 = %T\n", a );
               fmt.Printf("第 2 行 - b 變量類型爲 = %T\n", b );
               fmt.Printf("第 3 行 - c 變量類型爲 = %T\n", c );

               /*  & 和 * 運算符實例 */
               ptr = &a     /* 'ptr' 包含了 'a' 變量的地址 */
               fmt.Printf("a 的值爲  %d\n", a);
               fmt.Printf("ptr 的值爲  %v\n", &ptr);
               fmt.Printf("*ptr 爲 %d\n", *ptr);
            }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章