本篇文章主要介紹程序結構相關的知識,具體包括條件語句、循環、函數和指針等內容。編程
給定一個天然數v,若是它在0-100之間則返回v,若大於100則返回100,小於0則返回0,使用Go語言實現的代碼以下:ide
package main import "fmt" func ifTest(v int) int{ if v >100 { //if的條件裏面不須要括號 return 100 }else if v <0 { return 0 }else { return v } } func main() { var a int = ifTest(5) fmt.Println(a) } //運行結果: 5
注意到沒有if的條件裏面不須要括號,建立的文件中不能包含下劃線。func ifTest(v int) int
中參數v的前面不須要添加var
關鍵詞,後面的int則是該函數的返回結果。函數式編程
如今來使用Go語言來讀取某個文件的信息,如test.txt
中的內容,相應的代碼以下:函數
package main import ( "fmt" "io/ioutil" ) func readFieTest(){ const filename = "test.txt" contents, errorinfo :=ioutil.ReadFile(filename) //var contents ,errorinfo = ioutil.ReadFile(filename) if errorinfo != nil { fmt.Println(errorinfo) }else{ fmt.Printf("%s\n",contents) } } func main() { readFieTest() }
讀取文件須要採用ioutil包中的ReadFile函數,查看源碼可知該函數一次能夠返回兩個值:ui
func ReadFile(filename string) ([]byte, error) { ...... }
if errorinfo != nil
中的nil就是無的意思,此處就是產生了錯誤,能夠參考這篇文章瞭解更多關於nil的信息:理解Go語言的nil 。其實上面那種方式不是很簡介,可使用相似於Java中的三元表達式:.net
package main import ( "fmt" "io/ioutil" ) func readFieTest(){ const filename = "test.txt" if contents, errorinfo := ioutil.ReadFile(filename) ;errorinfo != nil { //先運行前半句後進行判斷 fmt.Println(errorinfo) }else { fmt.Printf("%s",contents) } } func main() { readFieTest() }
發現沒有if的條件裏能夠進行賦值,且if條件裏賦值的變量做用域就是這個if語句。接下來聊一聊switch,不少語言中都有switch。指針
switch後面是能夠接表達式的(也能夠不接),使用Go實現計算某兩個整數的加減乘除的功能,相應的代碼以下:code
package main import "fmt" func eval(a, b int,operation string) int { var result int switch operation { case "+": result = a +b case "-": result = a-b case "*": result = a*b case "/": result = a/b default: panic("不支持的運算方式"+operation) //這個panic就是報錯,讓程序停下來 } return result } func main() { test:= eval(3,4,"*") fmt.Println(test) } //運行結果: 12
細心的你發現什麼奇特之處麼?對,裏面沒有break
,由於Go語言中的switch
會自動break,除非使用了fallthrough
。而在C、C++或者是Java中你要麼在後面添加break要麼添加continue。對象
再來舉一個例子,用於判斷學生成績狀況:當分數小於60,則顯示不及格;60-69爲及格;70-79爲中等;80-89爲良好;90-100爲優秀。使用Go語言實現的代碼以下:blog
package main import "fmt" func scoreTest(score int)string { var result string = "" switch { case score <0 ||score >100 : panic(fmt.Sprintf("無效的分數:%d",score)) //若是這個條件成立,則程序再也不往下執行 case score <60: result = "不及格" case score<70: result = "及格" case score <80: result = "中等" case score <90: result = "良好" case score <=100: result = "優秀" } return result } func main() { fmt.Println( scoreTest(59), scoreTest(62), scoreTest(77), scoreTest(84), scoreTest(99), //scoreTest(-99), ) } //運行結果: 不及格 及格 中等 良好 優秀
若是程序知足panic的要求,則程序會中止運行。switch後面能夠沒有表達式
使用Go語言實現求解0-指定數字內的數字之和,如100之內整數的和,相應的代碼以下:
package main import "fmt" func sumTest(a int) int { sum := 0 for i :=0;i<=a;i++ { sum+=i } return sum } func main() { fmt.Println(sumTest(100)) }
上面使用了for循環,能夠發現這個for循環的格式除了條件中不包含括號之外,其實和Java,JavaScript的代碼徹底一致。且你們要學會在函數中儘可能使用:=
的方式替代var
來聲明變量。
for的條件中不包含括號,且條件中可省略初始條件,結束條件以及遞增表達式
再來看一個例子,將整數轉換成二進制的表達式,相應的代碼以下:
package main import ( "fmt" "strconv" ) func intToBinary(n int)string { result := "" for ;n>0;n/=2{ //省略初始條件,至關於while lsb := n%2 result = strconv.Itoa(lsb) +result } return result } func main() { fmt.Println( intToBinary(5), // 101 intToBinary(13), //1101 intToBinary(121242), ) }
再來換一種方式讀取以前那個test.txt文件中的內容,如今是一行行的進行讀取:
//一行行讀取 func printFileTest(filename string){ file, err :=os.Open(filename) if err != nil{ panic(err) //程序停下來去報錯 }else{ scanner := bufio.NewScanner(file) for scanner.Scan(){ // 這裏既沒有開始條件,也沒有遞增條件,只有結束條件,此時分號均可以不寫,Go語言中沒有while fmt.Println(scanner.Text()) //輸出 } } } func main() { printFileTest("test.txt") }
在這段代碼裏面for中既沒有開始條件,也沒有遞增條件,只有結束條件,那麼此時的分號均可以不寫,記住Go語言中沒有while。由於while的功能和for類似,因此Go語言中就沒有必要存在while這個關鍵詞了。
當for中什麼也不加,則變成了一個死循環,就至關於其餘語言中的while true。Go語言中的死循環實現起來很是簡單,那是由於後面會常用到死循環。
簡單總結一下循環語句的特色:一、for和if條件後面沒有括號;二、if條件裏面也能夠定義變量;三、Go語言中沒有while;四、switch中不須要定義break,也能夠直接switch多個語句。
其實在前面咱們就使用了func
這個關鍵詞用於定義函數,函數定義的格式爲:
func 函數名稱(參數名稱,參數類型)返回值類型{ ...... }
須要說明的是,Go語言的函數能夠有多個返回值的,且類型能夠不相同:
package main import "fmt" //求解兩個數的和 func sumTest(a,b int)int{ return a+b } //求兩個數相除的商及餘數 func divTest(a ,b int) (int,int, string) { return a/b, a%b, "你好" } func main() { fmt.Println(sumTest(3,6)) fmt.Println(divTest(13, 4)) } //運行結果: 9 3 1 你好
在上面的代碼中不知道返回的究竟是什麼,只知道都是int類型,其實能夠像聲明變量的方式那樣給返回值設置名稱:
//求兩個數相除的商及餘數 func divTest(a ,b int) (q, r int, s string) { return a/b, a%b, "你好" }
因爲Go語言很是嚴格,定義的變量必定要使用,若是函數有多個返回值,咱們只想取某個值時,那麼其他的變量可使用匿名變量_
來接收。儘管Go語言支持返回多個類型值,可是不要亂用,通常返回兩個,前者是數據,後者是錯誤nil
,以下圖所示。將前面實現兩個數的四則運算的相關代碼進行改寫:
package main import "fmt" func calcTest(a, b int,operation string ) (int, error) { switch operation { case "+": return a+b, nil case "-": return a-b,nil case "*": return a*b,nil case "/": return a/b,nil default: return 0,fmt.Errorf("不支持的運算操做:%s",operation) } } func main() { fmt.Println(calcTest(3,5,"+")) } //運行結果: 8 <nil>
上述代碼其實還不夠完善,在main方法中對正常與否須要進行判斷:
func main() { if result ,err:= calcTest(3,5,"+");err != nil{ //程序運行存在錯誤 fmt.Println("程序運行存在錯誤",err) }else{ fmt.Println(result) } }
在Go語言中函數能夠返回多個值,且能夠給多個值聲明名稱,可是返回多個值的狀況僅僅適用於很是簡單的函數,不過取不取名字和調用者無關。
Go語言是函數式編程,函數是一等公民(Python中也是),函數裏面的參數,返回值裏面均可以包含函數。經過前面求兩個數的四則運算這個例子進行改寫,實現將函數做爲參數:
Go語言沒有其餘語言中的默認參數、可變參數、函數重載等,只有一個可變參數列表:
//求可變參數列表中參數之和 func dynamicVariable(values ... int)int { sum :=0 for i:=range values{ sum+=values[i] } return sum } func main() { fmt.Println(dynamicVariable(1,2,3,4,5,6)) } //運行結果: 21
函數小結:一、函數返回值的類型寫在最後面;二、函數能夠返回多個值;三、函數可做爲參數進行使用;四、沒有默認參數和可選參數,函數重載等。
你們不要聽到指針就懼怕,Go語言中的指針和C語言中的指針差異很大(Go語言中的指針不能運算,而C語言中卻能夠),比C中的指針簡單多了。
看到這裏就必須談到一個老生常談的問題:Go語言中的參數傳遞是值傳遞仍是引用傳遞?在C和C++中既能夠值傳遞也能夠引用傳遞。Java和Python絕大部分都是引用傳遞,除了系統的自建類型之外。那麼什麼是值傳遞?什麼是引用傳遞呢?咱們經過C++中的一段代碼進行了解(C++中使用&
表示引用傳遞):
void pass_by_value(int a){ //值傳遞 a++; } void pass_by_guide(int& a){ //引用傳遞 a++; } int main(){ int a =3; pass_by_value(a) printf("值傳遞之後的值爲:%d\n",a); pass_by_guide(a) printf("引用傳遞之後的值爲:%d\n",a); } //運行結果: 3 4
pass_by_value是值傳遞,會將a的值從main函數中拷貝一份到pass_by_value函數中,真正做了一份拷貝,拷貝進去的a加了1,那麼main函數中的a並無發生變化,沒有動依舊是3。pass_by_guide是引用傳遞,它不會拷貝,此時main函數中的a和pass_by_guide中的a實際上是引用了同一個變量a,所以在pass_by_guide函數中進行了加1操做,天然main函數中的a也會發生變化,所以就變成了4。值傳遞就是拷貝,原來值不會發生變化;引用傳遞不會拷貝,會致使原來的值發生變化。
**Go語言只有值傳遞一種方式。**Go語言中的參數須要配合其指針來使用,具體分狀況:
上面這種就是值傳遞,二者沒有影響。下面是使用到了指針的狀況:
左側是一個int類型名爲a的變量,右側是一個int類型名爲aa的指針,經過指針實現至關於引用傳遞的效果,把a的地址給了你之後,能夠修改a的值。這些都是基本數據類型,再來嘗試一個自定義類型:
當把左側的book對象傳給右側的read函數時,通常這個book對象自己一般包含指向data的一個指針,而後拷貝一份到右側函數中,右側的book對象也有一個pdata,可是是指向同一個data,其實就是拷貝了同一份指針。所以在Go語言中,自定義類型的時候須要考慮把它做爲一個值仍是一個指針來用。這裏的book其實就是做爲一個值來用。
用一個交換兩個對象的值這個例子來加深你們的印象:
//交換兩個對象的值 func swap(a,b int) { a,b = b ,a } func main() { a ,b := 1,2 swap(a,b) fmt.Println(a, b) } //運行結果: 1,2
你會發現這個函數沒有用,兩個數值並無發生交換,的確是這樣的,那是由於這個須要藉助於指針來完成:
//交換兩個對象的值 func swap(a,b *int) { *a,*b = *b ,*a //聲明指針須要使用* } func main() { a ,b := 1,2 swap(&a,&b) //傳遞地址須要使用& fmt.Println(a, b) } //運行結果: 2,1
不過這種看起來挺麻煩的,其實以前的代碼不是沒有起做用,而是沒有將結果進行返回,修改一下代碼實際上是能夠的:
func swapTest(a,b int)(int ,int) { return b ,a } func main() { a ,b := 1,2 a, b = swapTest(a,b) fmt.Println(a, b) } //運行結果: 2,1
這樣就經過接收函數的返回值,進而實現交換兩個數值的目的。至此程序結構部分就介紹到這裏,後續內容不發了,賊累,去我博客上看!