Go語言基礎(七)—— Go語言for迴圈語句、Go字串、Go語言函式
for迴圈
Go語言的For迴圈有3種形式,只有其中的一種使用分號,和C語言種的for一樣:
for init; condition; post { }
和C語言種while一樣:
for condition { }
說明:
- init: 一般為賦值表示式,給控制變數賦初值;
- condition: 關係表示式或邏輯表示式,迴圈控制條件;
- post: 一般為賦值表示式,給控制變數增量或減量。
for 語句執行過程如下:
①先對錶達式 1 賦初值;
②判別賦值表示式 init 是否滿足給定條件,若其值為真,滿足迴圈條件,則執行迴圈體內
語句,然後執行 post,進入第二次迴圈,再判別 condition;否則判斷 condition 的值為假,
不滿足條件,就終止 for 迴圈,執行迴圈體外語句。
for 迴圈的 range 格式可以對 slice、map、陣列、字串等進行迭代迴圈。格式如下:
for key, value := range oldMap {
newMap[key] = value
}
For迴圈的巢狀:
for [condition | ( init; condition; increment ) | Range]
{
for [condition | ( init; condition; increment ) | Range]
{
statement(s);
}
statement(s);
}
迴圈控制語句
迴圈控制語句可以控制迴圈體內語句的執行過程。GO 語言支援以下幾種迴圈控制語句:
- break語句:經常用於終端當前for迴圈或跳出switch語句
- continue語句:跳過當前迴圈的剩餘語句,然後繼續進行下一輪迴圈。
- goto語句 :將控制轉移到被標記的語句
break語句:跳出迴圈
Go 語言中 break 語句用於以下兩方面:
1. 用於迴圈語句中跳出迴圈,並開始執行迴圈之後的語句。
2. break 在 switch(開關語句)中在執行一條 case 後跳出語句的作用。
continue語句
Go 語言的 continue 語句 有點像 break 語句。但是 continue 不是跳出迴圈,而是跳過當前迴圈執行下一次迴圈語句。for 迴圈中,執行 continue 語句會觸發 for 增量語句的執行。
goto
Go 語言的 goto 語句可以無條件地轉移到過程中指定的行。goto 語句通常與條件語句配合使用。可用來實現條件轉移, 構成迴圈,跳出迴圈體等功能。但是,在結構化程式設計中一般不主張使用 goto 語句, 以免造成程式流程的混亂,使理解和除錯程式都產生困難。
無限迴圈
如果迴圈中條件語句永遠不為 false 則會進行無限迴圈,我們可以通過 for 迴圈語句中只設置一個條件表示式來執行無限迴圈:
package main
import "fmt"
func main() {
for true {
fmt.Printf("這是無限迴圈。\n");
}
}
Go字串
在 Go 程式設計中廣泛使用的字串是隻讀位元組。在 Go 程式語言中,字串是切片。Go 平臺提供了各種庫來操作字串。
- unicode
- 正則表示式
- 字串
建立字串
var greeting = "Hello world!"
每當遇到程式碼中的字串時,編譯器將建立一個字串物件,其值為“Hello world!”。字串文字持有有效的 UTF-8 序列稱為符文。字串可儲存任意位元組。注意:字串文字是不可變的,因此一旦建立後,字串文字就不能更改了。
字串長度
len(str)方法返回包含在字串文字中的位元組數。請參考以下程式碼示例
package main
import "fmt"
func main() {
var greeting = "Hello world!"
fmt.Printf("String Length is: ")
fmt.Println(len(greeting))
}
上面程式碼執行後,將產生以下結果:
String Length is : 12
連線字串
strings 包包含一個用於連線多個字串的 join()方法,其語法如下:strings.Join(sample, " ")Join 連線陣列的元素以建立單個字串。第二個引數是分隔符,放置在陣列的元素之間。
案例:
package main
import (
"strings"
"fmt"
)
func main() {
var a []string = []string{"hello","world"}
fmt.Println(strings.Join(a,"2"))
}
結果為:
hello2world
字串輸出格式化
Go 語言為 printf 傳統中的字串格式化提供了極好的支援。 以下是常見字串 格式化任務的一些示例。 Go 提供了幾種列印“動詞”,設計用於格式化一般的值。 例如,列印 point 結構的 一個例項。 如果值是一個結構體,%+v 變體將包括結構體的欄位名。 %#v 變體列印值的 Go 語法表示,即將生成該值的原始碼片段。 要列印值的型別,請使用%T。格式化布林是比較直截了當的。有許多格式化整數的 選項。對於標準的 base-10 格式化,請使用%d。
Go語言函式
函式是基本的程式碼塊,用於執行一個任務。 Go 語言最少有個 main() 函式。 你可以通過函式來劃分不同功能,邏輯上每個函式執行的是指定的任務。 函式宣告告訴了編譯器函式的名稱,返回型別,和引數。 Go 語言標準庫提供了多種可動用的內建的函式。例如,len() 函式可以接受不同型別引數並返回該型別的長度。如果我們傳入的是字串則返回字串的長度,如果傳入的是陣列,則返回陣列中包含的元素個數。
函式定義
Go語言函式定義格式如下:
func function_name( [parameter list] ) [return_types] {
函式體
}
函式定義解析:
• func:函式由 func 開始宣告
• function_name:函式名稱,函式名和引數列表一起構成了函式簽名。
• parameter list:引數列表,引數就像一個佔位符,當函式被呼叫時,你可以將值傳遞給參
數,這個值被稱為實際引數。引數列表指定的是引數型別、順序、及引數個數。引數是可選 的,也就是說函式也可以不包含引數。
• return_types:返回型別,函式返回一列值。return_types 是該列值的資料型別。有些功能 不需要返回值,這種情況下 return_types 不是必須的。
• 函式體:函式定義的程式碼集合。
當有多個相同型別的連續引數時,可以省略型別引數的型別名稱,直到宣告該型別 的最後一個引數。例如:
func plusPlus(a, b, c int) int {
return a + b + c
}
示例:以下例項為 max() 函式的程式碼,該函式傳入兩個整型引數 num1 和 num2,並返回這兩個參
數的最大值:
/* 函式返回兩個數的最大值 */
func max(num1, num2 int) int { /* 宣告區域性變數 */
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}
函式呼叫
當建立函式時,你定義了函式需要做什麼,通過呼叫該函式來執行指定任務。
呼叫函式,向函式傳遞引數,並返回值,例如:
package main
import "fmt"
func main() { /* 定義區域性變數 */
var a int = 100
var b int = 200
var ret int
/* 呼叫函式並返回最大值 */
ret = max(a, b)
fmt.Printf( "maxNum= : %d\n", ret )
}
/* 函式返回兩個數的最大值 */
func max(num1, num2 int) int { /* 定義區域性變數 */
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}
以上例項在 main() 函式中呼叫 max()函式,執行結果為:
最大值是 : 200
函式返回多個值
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("Mahesh", "Kumar")
fmt.Println(a, b)
}
以上例項執行結果為:
Kumar Mahesh
可變引數函式
可變引數的函式可以用任何數量的引數來呼叫。 例如,fmt.Println()就是一個常 見的可變函式。 下面的例子將任意數量的 int 作為引數。可變引數的函式可以通過單獨的引數以通 常的方式呼叫。 如果已經在一個切片中有多個引數,使用 func(slice ...)函式將它們應用到一 個可變函式。
package main
import "fmt"
// 這個函式可以傳入任意數量的整型引數
func sum(nums ...int) {
fmt.Print(nums, " ")
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
func main() {
// 支援可變長引數的函式呼叫方法和普通函式一樣
// 也支援只有一個引數的情況
sum(1, 2)
sum(1, 2, 3)
// 如果你需要傳入的引數在一個切片中,像下面一樣
// "func(slice...)"把切片打散傳入
nums := []int{1, 2, 3, 4}
sum(nums...)
}
函式形參的副本機制
預設情況下,Go 語言使用的是值傳遞,即在呼叫過程中不會影響到實際引數。 傳遞是指在呼叫函式時將實際引數複製一份傳遞到函式中,這樣在函式中如果對引數進行修改,將不會影響到實際引數。 預設情況下,Go 語言使用的是值傳遞,即在呼叫過程中不會影響到實際引數。
以下定義了swap()函式
/* 定義相互交換值的函式 */
func swap(x, y int) int {
var temp int
temp = x /* 儲存 x 的值 */
x = y /* 將 y 值賦給 x */
y = temp /* 將 temp 值賦給 y*/
return temp;
}
接下來讓我們使用值傳遞來呼叫swap()函式。
package main
import "fmt"
func main() {
/* 定義區域性變數 */
var a int = 100
var b int = 200
fmt.Printf("交換前 a 的值為 : %d\n", a )
fmt.Printf("交換前 b 的值為 : %d\n", b )
/* 通過呼叫函式來交換值 */
swap(a, b)
fmt.Printf("交換後 a 的值 : %d\n", a )
fmt.Printf("交換後 b 的值 : %d\n", b )
}
/* 定義相互交換值的函式 */
func swap(x, y int) int {
var temp int
temp = x /* 儲存 x 的值 */
x = y /* 將 y 值賦給 x */
y = temp /* 將 temp 值賦給 y*/
return temp;
}
以上程式碼執行結果為:
交換前 a 的值為 : 100
交換前 b 的值為 : 200
交換後 a 的值 : 100
交換後 b 的值 : 200
引數的引用傳遞
引用傳遞是指在呼叫函式時將實際引數的地址傳遞到函式中,那麼在函式中對引數所進行的修改,將影響到實際引數。 引用傳遞指標引數傳遞到函式內,以下是交換函式 swap() 使用了引用傳遞:
/* 定義交換值函式*/
func swap(x *int, y *int) {
var temp int
temp = *x /* 保持 x 地址上的值 */
*x = *y /* 將 y 值賦給 x */
*y = temp /* 將 temp 值賦給 y */
}
以下我們通過使用引用傳遞來呼叫 swap() 函式:
package main
import "fmt"
func main() { /* 定義區域性變數 */
var a int = 100
var b int= 200
fmt.Printf("交換前,a 的值 : %d\n", a )
fmt.Printf("交換前,b 的值 : %d\n", b )
/* 呼叫 swap() 函式
* &a 指向 a 指標,a 變數的地址
* &b 指向 b 指標,b 變數的地址
*/
swap(&a, &b)
fmt.Printf("交換後,a 的值 : %d\n", a )
fmt.Printf("交換後,b 的值 : %d\n", b )
}
func swap(x *int, y *int) {
var temp int
temp = *x /* 儲存 x 地址上的值 */
*x = *y /* 將 y 值賦給 x */
*y = temp /* 將 temp 值賦給 y */
}
執行結果為:
交換前,a 的值 : 100
交換前,b 的值 : 200
交換後,a 的值 : 200
交換後,b 的值 : 100
函式作為值
Go 語言可以很靈活的建立函式,並作為值使用。以下例項中我們在定義的函式中初始化一個變數,該函式僅僅是為了使用內建函式 math.sqrt() ,例項為:
package main
import (
"fmt"
"math"
)
func main(){
/* 宣告函式變數 */
getSquareRoot := func(x float64) float64 {
return math.Sqrt(x)
}
/* 使用函式 */
fmt.Println(getSquareRoot(9))
}
以上程式碼執行的結果為:3
匿名函式
Go 語言支援匿名函式,可作為閉包。匿名函式是一個"內聯"語句或表示式。匿名函式的優越性在於可以直接使用函式內的變數,不必申明。
以下例項中,我們建立了函式 getSequence() ,返回另外一個函式。該函式的目的是在閉包
中遞增 i 變數,程式碼如下:
package main
import "fmt"
func getSequence() func() int {
i:=0
return func() int {
i+=1
return i
}
}
func main(){
/* nextNumber 為一個函式,函式 i 為 0 */
nextNumber := getSequence()
/* 呼叫 nextNumber 函式,i 變數自增 1 並返回 */
fmt.Println(nextNumber())
fmt.Println(nextNumber())
fmt.Println(nextNumber())
/* 建立新的函式 nextNumber1,並檢視結果 */
nextNumber1 := getSequence()
fmt.Println(nextNumber1())
fmt.Println(nextNumber1())
}
以上程式碼的結果為:
1
2
3
1
2
方法:包含了接收者的函式
Go 語言中同時有函式和方法。一個方法就是一個包含了接受者的函式,接受者可以是命名型別或者結構體型別的一個值或者是一個指標。所有給定型別的方法屬於該型別的方法集。語法格式如下:
func (variable_name variable_data_type) function_name() [return_type]{ /* 函式體*/
}
下面定義一個結構體型別和該型別的一個方法:
package main
import (
"fmt"
)
/* 定義結構體 */
type Circle struct {
radius float64
}
func main() {
var c1 Circle
c1.radius = 10.00
fmt.Println("Area of Circle(c1) = ", c1.getArea())
}
//該 method 屬於 Circle 型別物件中的方法
func (c Circle) getArea() float64 { //c.radius 即為 Circle 型別物件中的屬性
return 3.14 * c.radius * c.radius
}
以上程式碼執行結果為:
Area of Circle(c1) = 314