golang 数组 最后一个_Golang 速览
Go 或者你可以稱其為 Golang,是由谷歌團隊以及開源社區的貢獻者們開發的開源編程語言。2007 年 9 月 Go 的設計者之中就包括肯·湯普遜,并于兩年后宣布推出。
https://golang.org/ 是 Go 的官網;
https://golang.google.cn/ 如官網不存在你也可以選擇訪問這里;
https://github.com/unknwon/the-way-to-go_ZH_CN/blob/master/eBook/11.1.md 一本很版很棒的開源教程
接著在你的家目錄下為 Go 創建一個工作目錄,結構如下:
work├── bin│ └── hello├── pkg└── src └── github.com └── USERNAME └── hello └── hello.go該 work 工作目錄中的 src 存放著你工程中的源文件,bin 目錄中存放著編譯安裝之后的可執行文件,pkg 中則為包文件。
有關 go 程序的子命令,你都可以在命令行下獲得幫助:
go help目前你最常用到的就屬 go run 了,它會為你編譯并運行你所指定的源碼文件;go 有標準編碼風格,也為你提供了 go fmt 來格式化你的程序文件。
1
? ?
程序結構
package mainimport "fmt"func main() { fmt.Println("Hello, world")}經典的第一步,你的任一可執行 go 程序都必須在第一行指明其屬于 main 包;第二行導入實現了格式化輸入輸出的 fmt 包;主函數必須無參無返回值。
1.1
? ?
變量
你可以通過 var 關鍵字后跟標識符及其類型,完成變量的聲明,
var a intvar p1, p2 *intvar s string或者你也可以將變量的聲明于初始化結合起來,
var a int = 9var s string = "Hello, world"或者你也可以讓 go 編譯器自行推斷變量類型,
var a = 9var p = &a或者你還可以使用簡短格式,
i := 1s := "Hi"由于 go 語言同時賦值特性的存在,你可以一次同時初始化多個變量,
a, b, c := 1, 2.0, "three"當你需要交換兩變量時,已不需要再借助第三變量,
a, b = b, a還要說到的是 go 語言不準你聲明了變量卻不使用,這會導致你在編譯時錯誤。
1.2
? ?
分支
go 語言完全去掉了 if、for 語句條件判斷兩側的圓括號,并嚴格規定了花括號的使用格式,
if 1 != 2 { fmt.Println("True")} else { fmt.Println("Impossible")}你也可以在 if 語句的條件判斷中添加一個初始化語句,
if a := (1 != 2); a { fmt.Println(a)}go 只為你提供了強大的 for 循環,
for i := 0; i < 5; i++ { fmt.Println(i)}你可以按需求省去分號中任一部分的內容,或者全部省去變為一個死循環,
for { fmt.Println("Hi")}還有 for range 結構,可以幫你快速迭代一個集合,并返回每次的索引以及其值,
str := "Hello, world"for i, v := range str { fmt.Println(i, v)}如果后續你不需要用到其中的索引變量,但又要避免編譯時的變量未使用報錯,即可使用下劃線以丟掉,
for _, v := range str { // ...1.3
? ?
函數
go 函數定義由 func 關鍵字開始,并按需給出形參類型個數,與返回值類型及個數,
func sum2(a, b int) int { return a + b}是的,go 函數可以返回多個值(后面都省掉了包文件部分,)
func main() { fmt.Println(twoNums(1))}func twoNums(a int) (i, j int) { i = a - 1 j = a + 1 return i, j}并且 go 函數還能接收變長參數,只要當其最后一個參數為 ...type 的形式時即可,
func main() { hi() hi("Alice") hi("Alice", "Bob")}func hi(s ...string) { if len(s) == 0 { return } fmt.Printf("%T \n", s) // 輸出為:[]string,即為切片類型 for _, v := range s { fmt.Println("Hi,", v) }}在用三個點接受變長參數的情況下,其實相當于是在函數中的一個某類型的切片(slice)變量中存儲了參數值;后文會提到切片,因此你才能使用 for-range 進行迭代。
如果你選擇空接口(interface)作為變長參數的類型,那么你的函數將可以接受任意長度任意類型的變量,
package mainimport "fmt"type Any interface{}func main() { hiAny("Alice", true, 1, 2.0)}func hiAny(a ...Any) { for _, v := range a { fmt.Println("Hi,", v) } fmt.Printf("%T \n", a)}有關接口與 type 的使用,都放在后文中說,接下來是
1.4
? ?
匿名函數
直接理解匿名函數(anonymous function)就是不包含名字的函數,它除了不需名字外就跟普通函數的定義方式一樣了,還是以計算兩數和為例
func(a, b int) int { return a + b}那么現在的問題是,就既然它沒有名字那而你又需要調用。你有兩種選擇,第一是當你需要時就定義,定義完就直接用,
res := func(a, b int) int { return a + b}(1, 2)直接在函數體后跟上小括號就表示調用,并傳好要計算的數值同時還要接收好計算結果。
你的第二選擇,是將該匿名函數保存至一變量當中;
f := func(a, b int) int { return a + b}f(1, 2)好在你不用擔心變量 f 的類型,編譯器會明白它是函數類型類型的變量 —— 這是有點繞,func(int, int) int 這就是變量 f 的類型。
有意思的來了,既然如此那匿名函數也就能像變量一樣作為另一函數的返回值,看著有層次的寫法是這樣的,
func outer() (func(int, int) int) { fmt.Println("something in outer") return func(a, b int) int { return a + b }}這樣寫沒錯,但是 go fmt 會自動為你去掉 outer 函數返回值部分的小括號,后面的代碼中會遵循這種寫法。其中 outer 函數輸出部分亦為函數體,放在這里只是想說明外層函數當然不止僅僅用于返回求和函數這一個作用。下來是主函數,
func main() { fsum := outer() fmt.Println(fsum(1, 2))}對應前面,變量 fsum 的類型應為 outer() 函數的返回值類型:func(int, int) int ,接收兩整形形參返回一整形的函數類型;接著再調用它并完成一與二的求和運算。
上面的例子好像除了麻煩并沒有帶來什么別的東西,不過這種返回一個函數的函數也被成為工廠函數,當你需要一系列相似的函數時就會用到。這里以不同的打招呼方式為例,當你遇見 Alice 和 Bob 的時候要說 hi,而遇見世界的時候要說你好,
package mainimport "fmt"func main() { sayHiTo := MakeGreetPrefix("Hi, ") sayHelloTo := MakeGreetPrefix("Hello, ") sayHiTo("Alice") sayHiTo("Bob") sayHelloTo("world")}func MakeGreetPrefix(greeting string) func(string) { return func(name string) { fmt.Println(greeting + name) }}就像這樣你無需將重復的 Print 實現兩次,你只需要通過工廠函數來實現每次不同的招呼方式即可。
1.5
? ?
數組與切片
數組就是同一元素的集合,你可以像下面這樣聲明一包含 5 個整形默認值為零的數組,并輸出其類型,
func main() { var a [5]int fmt.Printf("%T\n", a)}// output:[5]int從結果你會發現,在 go 中連數組的長度都算作了數組類型。數組是固定長度你無法為它重新重新定義大小,但是動態長度的切片(slice)在 go 中更為常用。
var a = [5]int{1, 2, 3, 4, 5}s1 := a[1:3]s2 := a[:]通過同一個數組的兩個不同索引來界定一個切片時,你創建的切片門都會指向那個關聯數組;因此傳參給 go 函數時使用數組會造成額外的復制浪費,而使用切片則傳遞了索引。還有內建函數 make,在指明切片長度后會為你創建一全零數組同時返回切片,
s := make([]int, 10)這是取自官網的圖片與說明:切片是一數組的描述符,它包含著一個指向關聯數組的指針、長度(切片涉及到的數組元素)以及容量(關聯數組大小。)
2
? ?
結構與方法
結構(struct)是字段(field)的集合;字段為組成結構體的數據,并可通過 .(點)訪問其字段。
type Person struct { name string age int}func main() { p1 := Person{"Alice", 4} fmt.Println(p1.name) p1.age = 5 fmt.Println(p1.age)}go 在通過指針訪問結構字段時,你不需要自己進行解引用,
p2 := new(Person)p2.name = "Bob"fmt.Println(p2)go 中沒有對象的概念,也就自然沒有所謂構造函數一說,但你可以通過以 New 開頭命名的結構工廠來初始化對象,
func NewPerson(name string, age int) *Person { if age < 0 { return nil } return &Person{name, age}}func main() { p3 := NewPerson("Bob", 7)}當結構中包含一個或多個沒有名字的字段時,這些字段被稱為(anonymous field)匿名字段或內嵌字段,其只有類型名是必須的。當一結構體作為匿名字段被內嵌在另一結構體時,便可以與面向對象中的繼承相比較。
type Man struct { Person gender string}func main() { p4 := Man{Person{"Bob", 7}, "male"} fmt.Println(p4)}3
? ?
方法
方法 method 定義于 go 的類型之上,即在定義函數的關鍵字 func 與函數名之間加上一個接收者變量;意為這個方法是作用在這個接收者類型之上的。
func (m Man) Eat() { fmt.Println("I ate an apple.")}當使用值類型的接收者時,表現會跟普通的函數一樣,操作的是原數據的一份拷貝?;蛘吣阋部梢詫⒔邮苷哳愋投x為指針,這樣便可直接修改指針所指向的值,
func (m *Man) GrowUp(n int) { m.age = m.age + n}func main() { p4 := Man{Person{"Bob", 7}, "male"} p4.Eat() p4.GrowUp(1) fmt.Println(p4)}3.1
? ?
接口
對接口(interface)類型的定義是一組方法集,之后的類型有實現了同名方法的就可以認為它也實現了這個接口,因此接口類型的變量就可以容下該類型的變量。
現在上面的例子中添加一個 Tiger 結構,與人結構一樣,老虎也需要有吃這個方法,
type Tiger struct { name string age int}func (t Tiger) Eat() { fmt.Println("I do not eat apples.")}再來定義一個名為 Eater 的接口,其中就包含有人與老虎結構共實現了的 Eat() 這個方法,
type Eater interface { Eat()}創建好接口類型變量后,就可以讓他容下實現了同名方法的 Tiger 結構了,再當在接口類型變量上調用 Eat() 方法時,就會表現出 Tiger 作為接收者的方法了,
var eatIntf Eater = Tiger{"BagCat", 3}eatIntf.Eat()當然還可以用到循環之中,這就有點像是所謂的多態了,
t1 := Tiger{"BagCat", 3}eatIntf := []Eater{p4, t1}for _, e := range eatIntf { e.Eat()}本文的最后就到了前文提到過的空接口了,接口類型說的是誰實現了我有的方法,我就能容下誰;既然任何類型都至少滿足了無方法,那么空接口也就自然能容下任何值了。
注:圖片均取自 golang.org!
總結
以上是生活随笔為你收集整理的golang 数组 最后一个_Golang 速览的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 电气工程师学python_Python
- 下一篇: win10图标变白纸_超详细的纯净版wi
