1. 程式人生 > 實用技巧 >Go語言學習之路-5-Go語言基礎使用者輸入&流程控制

Go語言學習之路-5-Go語言基礎使用者輸入&流程控制

目錄

獲取使用者輸入

有時候程式需要根據使用者的選擇來執行不同的程式碼邏輯,這個時候就需要獲取使用者的輸入了

  • fmt.Scan
  • fmt.Scanln
  • fmt.Scanf

fmt.Scan

例子

import "fmt"

func main() {
	fmt.Print("請輸入使用者名稱和年齡通過空格區別:")
	var user string
	var age int8
	// &符可以獲取變數的記憶體地址
	// 通過fmt.Scan方法可以把使用者輸入的內容,寫入到這個記憶體地址
	// 預設通過空格區分
	count, err := fmt.Scan(&user, &age)

	fmt.Println(count, err, user, age)
	fmt.Printf("輸入的個數:%d, 錯誤:%s, 使用者輸入user值:%s, 使用者輸入的age值:%d\n", count, err, user, age)
}

注意事項

上面的情況fmt.Scan需要捕獲兩個值,但是如果我們輸入完一個值後一直敲回車是獲取不到第二個值得

go run main.go
請輸入使用者名稱和年齡通過空格區別:eson



# 上面的空白是我一直在敲回車
1
# 輸出結果
2 <nil> eson 1
輸入的個數:2, 錯誤:%!s(<nil>), 使用者輸入user值:eson, 使用者輸入的age值:1

fmt.Scanln

例子

package main

import "fmt"

func main() {
	fmt.Print("請輸入使用者名稱和年齡通過空格區別:")
	var user string
	var age int8
	// &符可以獲取變數的記憶體地址
	// 通過fmt.Scan方法可以把使用者輸入的內容,寫入到這個記憶體地址
	// 這個和Scan的區別在於它的終止是通過換行符的當使用者輸入換行符後就會終止使用者輸入
	// 同樣是空格分隔
	count, err := fmt.Scanln(&user, &age)

	fmt.Println(count, err, user, age)
	fmt.Printf("輸入的個數:%d, 錯誤:%s, 使用者輸入user值:%s, 使用者輸入的age值:%d\n", count, err, user, age)
}

fmt.Scanf

例子

package main

import "fmt"

func main() {
	fmt.Print("請輸入使用者名稱和年齡通過空格區別:")
	var user string
	// var age int8
	// &符可以獲取變數的記憶體地址
	// 通過fmt.Scanf方法可以把使用者輸入的內容
	// 和上面的兩個區別: 可以通過特定格式獲取變數
	// 比如這裡面使用者輸入:我叫X
	// 就可以從使用者輸入的內容獲取X的值
	count, err := fmt.Scanf("我叫%s", &user)

	fmt.Println(count, err, user)
	fmt.Printf("輸入的個數:%d, 錯誤:%s, 使用者輸入user值:%s\n", count, err, user)
}

注意事項

雖然是可以通過特定的格式獲取,但是如果佔位符後面沒有區分會有錯誤處理,後續的話或許可以優化

package main

import "fmt"

func main() {
	fmt.Print("請輸入使用者名稱和年齡通過空格區別:")
	var user string
	// 如果提取佔位符後面沒有空格,go這裡就不好判斷
	// 如果我輸入我叫eson屬小豬的,本意是想獲取eson這個值
	// 結果變成了:eson屬小豬的
	// 加個空格就能解決這個問題
	count, err := fmt.Scanf("我叫%s屬小豬的", &user)

	fmt.Println(count, err, user)
	fmt.Printf("輸入的個數:%d, 錯誤:%s, 使用者輸入user值:%s\n", count, err, user)
}

讀取一行資料

上面的情況預設都是空格但是如果想獲取一行輸入怎麼搞

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	fmt.Print("請輸入一行資料:")

	reader := bufio.NewReader(os.Stdin)
	// line從stdin中讀取一行資料(一個換行符是1行)它是一個位元組的集合
	// 我們輸入的內容都會放在一個緩衝區裡面直到我們輸入回車
	// 如果我們一次性輸入的內如果過多超過了這個緩衝區
	// 那麼isPrefix將會設定為True
	// 意思是可以迴圈讀取它暫時用不到先忽略
	line, isPrefix, err := reader.ReadLine()
	// 我們在把位元組轉換成字串
	data := string(line)
	fmt.Printf("使用者輸入的一行資料:%s, 是否讀取完了:%t, 錯誤:%v\n", data, isPrefix, err)
}

流程控制

  • 一門語言的流程控制主要的作用做判斷,類似我們平時的,如果...那麼...否則....的概念
  • 用它來解決需要判斷的場景

流程控制有:iffor,switch語句是編寫一系列if-else語句的較短方法、後面函式會有一個goto它解決的問題是

if else(如果那麼)

if else語法

if 表示式1 {
    如果表示式1,成立執行的程式碼
} else if 表示式2 {
    如果表示式2,成立執行的程式碼
} else{
    上面的表示式都不成立執行的程式碼
}

if else例子

  • if邏輯從上至下執行,如果上面的匹配了就不往下走了
  • if 或者else if必須和表示式和{ 在同一行 else 也得和{在同一行

例子:

package main

import "fmt"

func main() {
	var name string
	fmt.Print("請輸入您的使用者:")
	fmt.Scanln(&name)

	if name == "admin" {
		fmt.Println("歡迎您:管理員")
	} else if name == "eson" {
		fmt.Println("歡迎你:豆豆")
	} else {
		fmt.Printf("歡迎您:%s\n", name)
	}
}

switch case

我們使用上面的if else,如果需要判斷的太多了怎麼辦?有沒有精簡點的?

package main

import "fmt"

func main() {
	var name string
	fmt.Print("請輸入您的使用者:")
	fmt.Scanln(&name)

	if name == "admin" {
		fmt.Println("歡迎您:管理員")
	} else if name == "eson" {
		fmt.Println("歡迎你:豆豆")
	} else if name == "alex" {
		fmt.Println("歡迎你:alex")
	}else {
		fmt.Printf("歡迎您:%s\n", name)
	}
}

可以通過switch case來搞定,看著就比較舒服了

package main

import "fmt"

func main() {
	var name string
	fmt.Print("請輸入您的使用者:")
	fmt.Scanln(&name)

	switch name {
	case "admin":
		fmt.Println("歡迎您:admin")
	case "eson":
		fmt.Println("歡迎您:eson")
	case "alex":
		fmt.Println("歡迎您:alex")
	default:
		fmt.Printf("歡迎您:%s\n", name)
	}
}

當然也可以在分支進行判斷

package main

import "fmt"

func main() {
	var age int
	fmt.Print("請輸入您的年齡:")
	fmt.Scanln(&age)

	switch {
	case age > 60:
		fmt.Println("老年人")
	case age > 30:
		fmt.Println("中年人")
	case age > 18:
		fmt.Println("成年人")
	default:
		fmt.Println("未成年人")
	}
}

注意事項

  • switch只能有一個default

for 迴圈

在Go語言中可以通過for來解決所有需要,重複迴圈的邏輯

for迴圈語句格式

for 初始語句;條件表示式;結束語句{
    迴圈體語句
}
  • 如果for迴圈表示式結果一直為true那麼將一直執行,直到條件表示式返回false時才自動退出迴圈

無限迴圈

package main

import (
	"fmt"
	"time"
)

func main() {
	for {
		fmt.Println(time.Now())
		time.Sleep(time.Second * 1)
	}
}

非無限迴圈

package main

import (
	"fmt"
	"time"
)

func main() {
	// i初始值為0 ; 當i小於等於0時結束; 每次迴圈i自動+1
	for i := 0; i <= 10; i++ {
		fmt.Println(time.Now())
		time.Sleep(time.Second * 1)
	}
}

continue停止執行continue後面的邏輯,開始繼續迴圈

package main

import (
	"fmt"
	"time"
)

func main() {
	// i初始值為0 ; 當i小於等於0時結束; 每次迴圈i自動+1
	for i := 0; i <= 10; i++ {
		fmt.Println(time.Now())
		time.Sleep(time.Second * 1)

		// 當i大於等於6 且 小於等於8的時候後面的邏輯就不執行了,繼續迴圈
		if i >= 6 && i <= 8 {
			continue
		}

		fmt.Printf("當前時間是第%d執行\n", i)
	}
}

// 效果就是: 6~8不會輸出當前是第幾次執行

break停止for迴圈

package main

import (
	"fmt"
	"time"
)

func main() {
	// i初始值為0 ; 當i小於等於0時結束; 每次迴圈i自動+1
	for i := 0; i <= 10; i++ {
		fmt.Println(time.Now())
		time.Sleep(time.Second * 1)

		// 當i大於等於5的時候,整個for迴圈就直接退出了
		if i >= 5{
			break
		}

		fmt.Printf("當前時間是第%d執行\n", i)
	}
}

goto通過標籤進行程式碼間的無條件跳轉

看下面的場景,再去巢狀迴圈的場景需要break兩次才能退出

package main

import "fmt"

func main() {
	breakFlag := false

	for i := 0; i <= 10; i++ {
		for j := 0; j <= 10; j++ {
			if j == 3 {
				breakFlag = true // 內層迴圈設定breakFlag為true
				break
			}
			fmt.Printf("%v-%v\n", i, j)
		}
		// 放成迴圈監聽這個breakFlag為True的時候退出外城迴圈
		if breakFlag {
			break
		}
	}
}

使用goto來解決

package main

import "fmt"

func main() {

	for i := 0; i <= 10; i++ {
		for j := 0; j <= 10; j++ {
			if j == 3 {
				goto breakFlag // 內層迴圈直接調到指定的flag

			}
			fmt.Printf("%v-%v\n", i, j)
		}
	}
breakFlag:
	fmt.Println("got直接跳到這裡退出邏輯")

}

輸出結果:
0-0
0-1
0-2
got直接跳到這裡退出邏輯