Go學習筆記
Go語言基礎語法
行分隔行
在 Go 程式中,一行代表一個陳述句結束,每個陳述句不需要像 C 家族中的其它語言一樣以分號 ; 結尾,
但是可以使用分號;結尾,如果當你將多個陳述句寫在同一行時,則必須使用分號;
一、變數
1.1 變數的宣告
功能:存盤用戶的資料
注意: 變數必須經過宣告才能開始使用
標準格式:
var 變數名 變數型別
變數的宣告以關鍵字 var 開頭,行尾不需要寫分號
package main
import ( "fmt" )
func main() {
var a int
var b string
var c []float32
var d func () bool
var e struct {
x int
}
}
代碼說明:
-
第3行,宣告一個整型型別的變數,可以保存整數數值,
-
第4行,宣告一個字串型別的變數,
-
第5行,宣告一個 32 位浮點切片型別的變數,浮點切片表示由多個浮點型別組成的資料結構,
-
第6行,宣告一個回傳值為布爾型別的函式變數,這種形式一般用于回呼函式,即將函式以變數的形式保存下來,在需要的時候重新呼叫這個函式,
-
第7行,宣告一個結構體型別的變數,這個結構體擁有一個整型的 x 欄位,
使用var關鍵字和括號批量宣告(推薦)
var (
a int
b string
c []float32
d func () bool
e struct {
x int
}
)
使用關鍵字var和括號,可以將一組變數定義放在一起,
1.2 初始化變數
變數的宣告可以包含初始值,每一個變數對應一個值,
如果初始化值已存在,則可以省略型別;變數會從初始值中獲得型別,
變數初始化的標準格式:
var 變數名 型別 = 運算式
簡化形式:
var 變數名 = 運算式
例如:
var x int = 100
可以寫成:
var x = 100
默認值:
沒有明確初始值的變數宣告會被賦予它們一個默認值:
整型和浮點型變數的默認值為 0,
字串變數的默認值為空字串,
布爾型變數默認為 bool,
切片、函式、指標變數的默認為 nil,
注意:變數已經被宣告過了,再次宣告并賦值,使用短變數宣告會編譯報錯
var p string
p := '123'
fmt.Println(p)
// 錯誤資訊:no new variables on left side of :=(44.4)
// var p 宣告了p變數, p := '123' 會再次宣告并賦值
注意:由于使用了 :=,而不是賦值的 =,因此推導宣告寫法的左值變數必須是沒有定義過的變數,若定義過,將會發生編譯錯誤,
注意:在多個短變數宣告和賦值中,至少有一個新宣告的變數出現在左值中,即便其他變數名可能是重復宣告的,編譯器也不會報錯,例如:
x, z := a, b
y, z := a, b
1.4 多個變數同時賦值
使用Go的“多重賦值特性”,可以輕松完成變數交換的任務,
package` `main
import` `"fmt"
func main() {
var a = 100
var b = 200
a, b = b, ago
fmt.Println(a, b)
}
多重賦值時,變數的左值和右值按從左到右的順序賦值,
1.5 匿名變數(_)
在使用多重賦值時,如果不需要在左值中接收變數,可以使用匿名變數,
匿名變數用一個下劃線 _ 來表示,使用匿名變數時,只需要在變數宣告的地方使用下劃線替換即可,例如:
var a int
a, _ = 100, 200
注意:匿名變數不占用命名空間,不會分配記憶體,匿名變數與匿名變數之間也不會因為多次宣告而無法使用,
package main
import ("fmt")
func main() {
a1, _ := getData()
_, b1 := getData()
fmt.Println(a1, b1)
}
type IntSlice []int
// 撰寫一個len方法,提供切片的長度
func (p IntSlice) Len() int { return len(p)}
// 根據提供i,j元素索引,兩個元素進行比較,回傳比較結果
func (p IntSlice) Less(i, j int) bool { return p[i] < p[j]}
// 根據提供i,j元素索引,交換兩個元素的值
func (p IntSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i]}
func getData() (int, int) {
return 200, 100
}
二、常量
常量是恒定不變的值,例如圓周率,
常量的宣告與變數類似,只不過是使用 const 關鍵字,
常量可以是字符、字串、布林值和數值,
常量不能用 := 語法宣告,
常量的宣告, 例如:
const pi = 3.1415926
注意:常量在宣告的時候必須賦值,
多個變數可以一起宣告,類似的,多個變數也可以一起宣告,例如:
const(
pi = 3.1415926
e = 2.718281
)
三、基本資料型別
Go語言中有豐富的資料型別,除了基本的整型、浮點型、布爾型、字串外,還有切片、結構體、函式、map、通道(channel)等,
Go 語言的基本型別和其他語言大同小異,
3.1 整型
整型可以分成以下兩個大類:
按長度分為:int8、int16、int32、int64
對應的無符號整型:uint8、uint16、uint32、uint64
其中,uint8 就是我們熟知的 byte 型.
3.2 浮點型
Go語言支持兩種浮點型數:
float32、float64.
注意:沒有float
Go語言的浮點型默認宣告為float64.
3.3 布爾型
布爾型資料只有 true(真)和 false(假)兩個值,
注意:
在Go語言中,
true和false均為小寫
不允許將整型強制轉換為布爾型
3.4 字串
字串的兩種表示形式:
\1. 雙引號,會識別轉義字符
\2. 反引號,不會識別轉義字符,以字串的原生形式輸出,包括換行和特殊字符,
3.4.1 字串常見轉義符
| 轉義符 | 含義 |
|---|---|
| \r | 回車符(回傳行首) |
| \n | 換行符 |
| \t | 制表符 |
| ' | 單引號 |
| " | 雙引號 |
| \ | 反斜杠 |
3.4.2 反引號定義多行字串
const str = ` 第一行
第二行
第三行
\r\n`
fmt.Println(str)
代碼運行結果:
第一行
第二行
第三行
\r\n
3.5 字符
字串中的每一個元素叫做“字符”,在遍歷或者單個獲取字串元素時可以獲得字符,
Go語言的字符有以下兩種:
- 一種是 uint8 型別,或者叫 byte 型,代表了 ASCII碼的一個字符,
- 另一種是 rune 型別,代表一個 UTF-8 字符,當需要處理中文、日文或者其他復合字符時,則需要用到 rune 型別,rune 型別實際是一個 int32,
四、資料型別的轉換
Go語言使用型別前置加括號的方式進行型別轉換,一般格式如下:
T(運算式)
其中,T 代表要轉換的型別,運算式包括變數、復雜算子和函式回傳值等,
注意:在型別轉換時,需要考慮兩種型別的關系和范圍,是否會發生數值截斷等,
package main
import "fmt"
func main(){
var n1 int = 20
var n2 float64 = float64(n1)
n2 = n2 + 3.6
var n3 int32 = int32(n2) // 當將一個float型別轉成 int時,是直接去掉小數點后的部分
fmt.Printf("n1 type=%T, val=%v; n2 type=%T, val=%v; n3 type=%T, val=%v\n",
n1, n1, n2, n2, n3, n3)
}
代碼運行結果:
n1 type=int, val=20; n2 type=float64, val=23.6; n3 type=int32, val=23
五 、指標
兩個核心:
一種是型別指標,允許對這個指標型別的資料進行修改, 傳遞資料使用使用指標,而無須拷貝資料 型別指標不能進行偏移和運算
二種是切片, 由指向起始元素的原始指標、元素數量和容量組成
5.1 認識指標地址和指標型別
每個變數在運行時都會被記憶體分配一個地址,這個地址代表變數在記憶體中的位置 使用“&”運算子放在變數前面對變數進行“取地址”操作 格式:
ptr := &variable //variable的型別為T
其中v代表被取地址的變數,被取地址的variable使用ptr變數進行接收,ptr的型別為“T”,稱作T的指標型別,“”代表指標
package main
import (
"fmt"
"math"
)
func main() {
var cat int = 1
var str2 string = "banana"
fmt.Printf("%p, %p\n", &cat, &str2)
}
//0xc00004e0e8, 0xc0000421f0 為cat,str2取地址后的指標值
注意:變數、指標和地址三種的關系是:每個變數都擁有地址,指標的值就是地址
5.2 從指標獲取指標指向的值
對變數“&”取地址操作后獲得這個變數的指標,對指標使用“*”操作,就是指標取值
package main
import (
"fmt"
"math"
)
func main() {
var house = "Malibu Point 10880, 90265"
// 對字串取地址,ptr1型別為*string
ptr1 := &house
// 列印ptr型別
fmt.Printf("ptr1 型別:%T\n", ptr1)
// 列印ptr指標地址
fmt.Printf("ptr1 地址:%p\n", ptr1)
// 對指標進行取值操作
value := *ptr1
// 取值后型別
fmt.Printf("value 型別:%T\n", value)
// value值
fmt.Printf("value:%s\n", value)
}
// ptr1 型別:*string
// ptr1 地址:0xc000042200
// value 型別:string
// value:Malibu Point 10880, 90265
總結:
取地址“&”和取值“”是一對互補運算子,“&”取地址,"&"根據地址取出地址指向的值
1.對變數進行其地址(&)操作,可獲得這個變數的指標變數
2.指標變數的值是指標地址
3.對指標變數進行取值()操作,可以獲得指標變數指向的原變數的值
5.3 使用指標修改值
x, y := 1,2
package main
import (
"fmt"
"math"
)
func main() {
//錯誤示例
swap1(&x, &y)
fmt.Println("x: ",x, "y:", y)
//x: 1 y: 2
//正確
swap(&x, &y)
fmt.Println("x: ", x, "y: ",y)
//x: 2 y: 1
}
// 交換函式
func swap(a, b *int) {
// 取a的指標的值,賦給臨時變數t
t := *a
//取b指標的值,賦值給a指標指向的變數
*a = *b
//a指標的值賦值給b指標指向的變數
*b = t
}
// 錯誤示例
func swap1(a, b *int) {
b, a = a, b
}
5.4 創建指標的另一種方法--new()函式
new(型別)
str3 := new(string)
*str3 = "ninja"
fmt.Println(*str3)
fmt.Println(str3)
//ninja
//0xc000042230
六、字串應用
6.1 計算機字串長度 -- len()
go 語言字串都是以UTF-8格式保存,每個中文占用3個字符
tip1 := "genji is a ninja"
fmt.Println(len(tip1))
// 16
tip2 := "忍者無敵"
fmt.Println(len(tip2))
//12
// 使用RuneCountInString()統計Uncode字符數量
fmt.Println(utf8.RuneCountInString("忍者"))
總結
- ASCII字串長度使用len()函式
- Unicode字串長度使用utf8.RuneCountInString()函式
6.2 遍歷字串 -- 獲取每個字串
兩種寫法
- 遍歷每一ASCII字符, 使用for回圈遍歷
theme := "阻擊 start"
for i := 0; i < len(theme); i++ {
fmt.Printf("ascii: %c %d\n", theme[i], theme[i])
}
// ascii: é 233
// ascii: ? 152
// ascii: ? 187
// ascii: ? 229
// ascii: ? 135
// ascii: ? 187
// ascii: 32
// ascii: s 115
// ascii: t 116
// ascii: a 97
// ascii: r 114
- 按Unicode字符遍歷字串
for _, s := range theme {
fmt.Printf("Unicode %c %d\n", s, s)
}
// Unicode 阻 38459
// Unicode 擊 20987
// Unicode 32
// Unicode s 115
// Unicode t 116
// Unicode a 97
// Unicode r 114
// Unicode t 116
總結:
- ASCII字串遍歷直接使用下標
- Unicode字串遍歷使用for range
6.3 獲取字串的某一段字符
string.Index() 在字串中搜索另一個子串
tracer := "努力擁抱每一天,不斷成長"
comma := strings.Index(tracer, "每一天")
posi := strings.Index(tracer[comma:], "成長")
fmt.Println(comma, posi, tracer[comma+posi:])
// 12 18 成長
總結:
- strings.Index:正向搜索子字串
- string.LastIndex: 反向搜索自字串
搜索的起始位置可以通過切片偏移制作
6.4 修改字串
go語言無法直接修改每一個字符元素,只能通過重新構造新的字串并賦值給原來的字串變數
angel := "Hero nerver die"
arrayBytes := []byte(angel)
for i := 5; i <= 10; i++ {
arrayBytes[i] = '-'
}
fmt.Println(arrayBytes)
// [72 101 114 111 32 45 45 45 45 45 45 32 100 105 101]
fmt.Println(string(arrayBytes))
// Hero ------ die
總結
- Go語言的字串是不可以改變的
- 修改字串時,可以將字串轉換為[]byte進行修改
- []byte 和string 可以通過強制型別轉換互換
6.5 連接字串
可以使用加號“+”連接 可以使用類似于StringBuilder的機制連接,更高效
hamer := "GO GO GO"
sickle := "You Can"
// 宣告位元組緩沖
var stringBuilder bytes.Buffer
// 將字串寫入緩沖區
stringBuilder.WriteString(hamer)
stringBuilder.WriteString(sickle)
//將緩沖以字串形式輸出
fmt.Println(stringBuilder.String())
// GO GO GOYou Can
- bytes.Buffer可以緩沖并寫入各種位元組陣列,字串也是一種字串陣列,使用writeString()
- 將需要連接的字串,通過bytes.Buffer宣告緩沖stringBuilder呼叫WriteString()方法寫入里面,
- 再通過stringBuilder.String()方法將緩沖轉換為字串
6.6 格式化
寫法: fmt.Sprintf(格式化樣式,引數串列)
格式化樣式:字串形式,格式化動詞以%開頭
引數串列:多個引數以逗號分隔,個數必須與格式化中樣式個數一一對應
var progress = 2
var target = 8
// 兩引數格式化
title := fmt.Sprintf("以完成%d個任務,還差%d個就完成", progress, target)
fmt.Println(title)
// 以完成2個任務,還差8個就完成
pi := math.Pi
// 按數值本身格式輸出
variant := fmt.Sprintf("%v %v %v", "月球基地", pi, true)
fmt.Println(variant)
// 月球基地 3.141592653589793 true
profile := &struct {
Name string
HP int
}{
Name: "stat",
HP: 150,
}
fmt.Printf("使用'%%+v' %+v\n", profile)
fmt.Printf("使用'%%#v' %#v\n", profile)
fmt.Printf("使用'%%T' %T\n", profile)
// 使用'%+v' &{Name:stat HP:150}
// 使用'%#v' &struct { Name string; HP int }{Name:"stat", HP:150}
// 使用'%T' *struct { Name string; HP int }
base64編碼解碼示例
package main
import (
"fmt"
"encoding/base64"
)
func main() {
// 需要處理的字串
message := "Away from keyboard. https://golang.org/"
// 編碼訊息, 傳入的字串需轉為位元組陣列,才能供這個函式使用
encodeMessage := base64.StdEncoding.EncodeToString([]byte(message))
// 輸出編碼完成的訊息
fmt.Println(encodeMessage)
// 解碼訊息
data, err := base64.StdEncoding.DecodeString(encodeMessage)
// 出錯處理
if err != nil {
fmt.Println(err)
} else {
fmt.Println(string(data))
}
// QXdheSBmcm9tIGtleWJvYXJkLiBodHRwczovL2dvbGFuZy5vcmcv
// Away from keyboard. https://golang.org/
}
七、列舉
7.1 列舉 -- 一組常量值
// 使用iota模擬列舉
type Weapon int
const (
Arrow Weapon = iota // 開始生成列舉值,默認為0
Shuriken
SniperRifle
Rifle
Blower
)
// 輸出所有列舉值
fmt.Println(Arrow, Shuriken, SniperRifle, Rifle, Blower)
var weapon Weapon = Blower
fmt.Println(weapon)
// 0 1 2 3 4
// 4
7.2 列舉--將列舉值轉換為字串
package main
import ("fmt")
// 宣告芯片型別
type ChipType int
const (
None ChipType = iota
GPU
CPU
)
func (c ChipType) String() string {
switch c {
case None:
return "None"
case GPU:
return "GPU"
case CPU:
return "CPU"
}
return "N/A"
}
func main() {
// 輸出CPU的值并以整型格式顯示
fmt.Printf("%s %d", CPU, CPU)
//CPU 2
}
八、 型別別名
8.1 區分型別別名與型別定義
型別別名的寫法:
type TypeAlias = Type
型別別名規定:
TypeAlias只是Type的別名,本質上TypeAlias與Type是同一個型別
// 將NewInt定義為int型別
type NewInt int
// 將int取一個別名叫IntAlias
type IntAlias = int
// 將a宣告為一個NewInt型別
var alias_a NewInt
fmt.Printf("a type: %T\n", alias_a)
// a type: main.NewInt
// 將a2宣告為IntAlias型別
var alias_a2 IntAlias
fmt.Printf("a2 type: %T\n", alias_a2)
// a2 type: int
8.2 非本地型別不能定義方法
不能為不在同一個包中宣告的型別定義方法,即不能為在其他包宣告的型別在本地包中定義方法
package main
import ("time")
// 2.8.2
// 定義time.Duration 的別名為MyDuration
type MyDuration = time.Duration
// 為MyDuration 添加一個函式
func (m MyDuration) EasySet(a String) {
}
func main() {
}
//# 2-base/2.2-data_type
//.\data_type.go:51:6: cannot define new methods on non-local type time.Duration
//.\data_type.go:51:31: undefined: String
//exit status 2
//Process exiting with code: 1
8.3 在結構體成員嵌入時使用別名
package main
import (
"fmt"
"reflect"
)
// 定義商標結構
type Brand struct {
}
// 為商標結構添加Show()方法
func (t Brand) Show() {
}
// 為Brand定義一個別名
type FakeBrand = Brand
// 定義車輛結構,嵌入商標結構
type Vehicle struct {
Brand
FakeBrand
}
func main() {
// 宣告變數 a 為車輛型別
var a Vehicle
// 指定呼叫FakeBrand的Show
a.FakeBrand.Show()
// 取a的型別反射物件
ta := reflect.TypeOf(a)
// 遍歷a的所有成員
for i := 0; i < ta.NumField(); i++ {
// ta 成員資訊
f := ta.Field(i)
// 列印成員的欄位名和型別
fmt.Printf("FieldName: %v, FieldType: %v\n", f.Name, f.Type.Name())
}
// FieldName: Brand, FieldType: Brand
// FieldName: FakeBrand, FieldType: Brand
go
}
總結:
- FakeBrand是Brand的一個別名,在Vehicel中嵌入FakeBrand和Brand,Vehicel的型別會以名字的方式保留在Vehicle的成員中
- FakeBrand和Brand 都有Show()方法, 呼叫時必須制定呼叫誰的, a.FakeBrand.Show()
九、條件陳述句
8.1 if陳述句
if 陳述句由布爾運算式后緊跟一個或多個陳述句組成,
語法
Go 編程語言中 if 陳述句的語法如下:
if 布爾運算式 {
/* 在布爾運算式為 true 時執行 */
}
注意:if陳述句一定要加{}
8.2 if...else陳述句
if 陳述句 后可以使用可選的 else 陳述句, else 陳述句中的運算式在布爾運算式為 false 時執行,
語法
Go 編程語言中 if...else 陳述句的語法如下:
if 布爾運算式 {
/* 在布爾運算式為 true 時執行 */
} else {
/* 在布爾運算式為 false 時執行 */
}
注意:每一個 if else 都需要加入括號 同時 else 位置不能在新一行
尋找到 100 以內的所有的素數:
package main
import "fmt"
func main(){
// var count,c int //定義變數不使用也會報錯
var count int
var flag bool
count=1
//while(count<100) { //go沒有while
for count < 100 {
count++
flag = true;
//注意tmp變數 :=
for tmp:=2;tmp<count;tmp++ {
if count%tmp==0{
flag = false
}
}
// 每一個 if else 都需要加入括號 同時 else 位置不能在新一行
if flag == true {
fmt.Println(count,"素數")
}else{
continue
}
}
}
8.3 switch case陳述句:
普通的switch陳述句:
var i = 0
switch i {
case 0:
case 1:
fmt.Println(“1”)
case 2:
fmt.Println(“2”)
default:
fmt.Println(“def”)
}
fallthrough陳述句:
var i = 0
switch i {
case 0:
fallthrough
case 1:
fmt.Println(“1”)
case 2:
fmt.Println(“2”)
default:
fmt.Println(“def”)
}
注:加了fallthrough后,會直接運行【緊跟的后一個】case或default陳述句,不論條件是否滿足都會執行,后面的條件并不會再判斷了,
注意:Go 沒有三目運算子,所以不支持*?: 形式的條件判斷,
十、for回圈
for 回圈是一個回圈控制結構,可以執行指定次數的回圈,
語法
Go 語言的 For 回圈有 3 種形式,只有其中的一種使用分號,
和 C 語言的 for 一樣:
for init; condition; post { }
和 C 的 while 一樣:
for condition { }
和 C 的 for(;?? 一樣:
for { }
- init: 一般為賦值運算式,給控制變數賦初值;
- condition: 關系運算式或邏輯運算式,回圈控制條件;
- post: 一般為賦值運算式,給控制變數增量或減量,
for陳述句執行程序如下:
- 1、先對運算式 1 賦初值;
- 2、判別賦值運算式 init 是否滿足給定條件,若其值為真,滿足回圈條件,則執行回圈體內陳述句,然后執行 post,進入第二次回圈,再判別 condition;否則判斷 condition 的值為假,不滿足條件,就終止for回圈,執行回圈體外陳述句,
for 回圈的 range 格式可以對 slice、map、陣列、字串等進行迭代回圈,格式如下:
for key, value := range oldMap {
newMap[key] = value
}
實體
計算 1 到 10 的數字之和:
實體
package main
import "fmt"
func main() {
sum := 0
for i := 0; i <= 10; i++ {
sum += i
}
fmt.Println(sum)
}
輸出結果為:
55
init 和 post 引數是可選的,我們可以直接省略它,類似 While 陳述句,
以下實體在 sum 小于 10 的時候計算 sum 自相加后的值:
實體
package main
import "fmt"
func main() {
sum := 1
for ; sum <= 10; {
sum += sum
}
fmt.Println(sum)
// 這樣寫也可以,更像 While 陳述句形式
for sum <= 10{
sum += sum
}
fmt.Println(sum)
}
輸出結果為:
16
16
無限回圈:
實體
package main
import "fmt"
func main() {
sum := 0
for {
sum++ // 無限回圈下去
}
fmt.Println(sum) // 無法輸出
}
要停止無限回圈,可以在命令視窗按下ctrl-c ,
For-each range 回圈
這種格式的回圈可以對字串、陣列、切片等進行迭代輸出元素,
實體
package main
import "fmt"
func main() {
strings := []string{"google", "runoob"}
for i, s := range strings {
fmt.Println(i, s)
}
numbers := [6]int{1, 2, 3, 5}
for i,x:= range numbers {
fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
}
}
以上實體運行輸出結果為:
0 google
1 runoob
第 0 位 x 的值 = 1
第 1 位 x 的值 = 2
第 2 位 x 的值 = 3
第 3 位 x 的值 = 5
第 4 位 x 的值 = 0
第 5 位 x 的值 = 0
十一、陣列
11.1 宣告陣列
Go 語言陣列宣告需要指定元素型別及元素個數,語法格式如下:
var variable_name [SIZE] variable_type
以上為一維陣列的定義方式,例如以下定義了陣列 balance 長度為 10 型別為 float32:
var balance [10] float32
11.2 初始化陣列
以下演示了陣列初始化:
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
初始化陣列中 {} 中的元素個數不能大于 [] 中的數字,
如果忽略 [] 中的數字不設定陣列大小,Go 語言會根據元素的個數來設定陣列的大小:
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
該實體與上面的實體是一樣的,雖然沒有設定陣列的大小,
balance[4] = 50.0
以上實體讀取了第五個元素,陣列元素可以通過索引(位置)來讀取(或者修改),索引從0開始,第一個元素索引為 0,第二個索引為 1,以此類推,

11.3 訪問陣列元素
陣列元素可以通過索引(位置)來讀取,格式為陣列名后加中括號,中括號中為索引的值,例如:
var salary float32 = balance[9]
11.4多維陣列
Go 語言支持多維陣列,以下為常用的多維陣列宣告方式:
var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type
以下實體宣告了三維的整型陣列:
var threedim [5][10][4]int
11.5初始化多維陣列
多維陣列可通過大括號來初始值,以下實體為一個 3 行 4 列的二維陣列:
a = [3][4]int{
{0, 1, 2, 3} , /* 第一行索引為 0 */
{4, 5, 6, 7} , /* 第二行索引為 1 */
{8, 9, 10, 11}, /* 第三行索引為 2 */
}
注意:以上代碼中倒數第二行的 } 必須要有逗號,因為最后一行的 } 不能單獨一行,也可以寫成這樣:
a = [3][4]int{
{0, 1, 2, 3} , /* 第一行索引為 0 */
{4, 5, 6, 7} , /* 第二行索引為 1 */
{8, 9, 10, 11}} /* 第三行索引為 2 */
11.6 訪問多維陣列
多維陣列通過指定坐標來訪問,如陣列中的行索引與列索引,例如:
val := a[2][3]
或
var value int = a[2][3]
以上實體訪問了二維陣列 val 第三行的第四個元素,
十二、函式
函式是基本的代碼塊,用于執行一個任務,
Go 語言最少有個 main() 函式,
你可以通過函式來劃分不同功能,邏輯上每個函式執行的是指定的任務,
函式宣告告訴了編譯器函式的名稱,回傳型別,和引數,
Go 語言標準庫提供了多種可動用的內置的函式,例如,len() 函式可以接受不同型別引數并回傳該型別的長度,如果我們傳入的是字串則回傳字串的長度,如果傳入的是陣列,則回傳陣列中包含的元素個數,
12.1 函式定義
Go 語言函式定義格式如下:
func function_name( [parameter list] ) [return_types] {
函式體
}
函式定義決議:
-
func:函式由 func 開始宣告
-
function_name:函式名稱,函式名和引數串列一起構成了函式簽名,
-
parameter list:引數串列,引數就像一個占位符,當函式被呼叫時,你可以將值傳遞給引數,這個值被稱為實際引數,引數串列指定的是引數型別、順序、及引數個數,引數是可選的,也就是說函式也可以不包含引數,
-
return_types:回傳型別,函式回傳一列值,return_types 是該列值的資料型別,有些功能不需要回傳值,這種情況下 return_types 不是必須的,
-
函式體:函式定義的代碼集合,
注意:
1.2.1 golang函式不支持多載,一個包不能有兩個函式名一樣的函式,
1.2.2 函式也是一種型別,一個函式可以賦值給變數,
12.2 函式回傳多個值
Go 函式可以回傳多個值,例如:
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("Google", "Runoob")
fmt.Println(a, b)
}
以上實體執行結果為:
Runoob Google
12.3 函式return值的幾種情況
分三種情況
(以下 “指定回傳值”這句話, 僅指return后面直接跟著的回傳值)
1.退出執行,不指定回傳值
(1) 函式沒有回傳值
package main
import (
"fmt"
)
func GetMoney(){
fmt.Println("money")
return
}
func main(){
GetMoney()
}
(2) 函式回傳值有變數名
package main
import (
"fmt"
)
func GetMoney() (_amount int){
_amount = 88
fmt.Println("money: ",_amount)
return
}
func main(){
var amount = GetMoney()
fmt.Println("money: ",amount)
}
2.退出執行,指定回傳值
package main
import (
"fmt"
)
func GetMoney() (_amount int){
fmt.Println("money: ",_amount)
return 88
}
func main(){
var amount = GetMoney()
fmt.Println("money: ",amount)
}
運行結果:
money: 0
money: 88
3.退出執行,指定回傳值和指定默認值
package main
import (
"fmt"
)
func GetMoney() (_amount int){
_amount = 99 //如果return后面沒有指定回傳值,就用賦給“回傳值變數”的值
fmt.Println("money: ",_amount)
return 88 //如果return后面跟有回傳值,就使用return后面的回傳值
}
func main(){
var amount = GetMoney()
fmt.Println("money: ",amount)
}
運行結果:
money: 99
money: 88
12.4 可變引數
- 0或多個引數
func add(arg…int) int {
}
- 1或多個引數
func add(a int, arg…int) int {
}
- 2或多個引數
func add(a int, b int, arg…int) int {
}
12.5 匿名函式
由一個不帶函式名的函式宣告和函式體組成,
func main() {
i := 1
go func(i int) {
time.Sleep(100*time.Millisecond)
fmt.Println("i =", i)
} (i)
i++
time.Sleep(1000*time.Millisecond)
}
十三、defer的用途
- 當函式回傳時,先執行return,后執行defer陳述句,因此,可以用來做資源清理、關閉句柄、鎖的釋放、資料庫連接釋放,
- 多個defer陳述句,按先進后出的方式執行,
- defer陳述句中的變數,在defer宣告時就決定了,
func a() {
i := 0
defer fmt.Println(i)
i++
return
}
關閉檔案句柄:
func read() {
file := open(filename)
defer file.Close()
//其他操作
}
鎖資源的釋放:
func read() {
mc.Lock()
defer mc.Unlock()
//其他操作
}
資料庫連接釋放:
func read() {
conn := openDatabase()
defer conn.Close()
//其他操作
}
十四、輸入的使用
1、輸入的使用
第一種寫法:fmt.Scanf("%d", &a)
第二種寫法:fmt.Scan(&a)
示例:
package main //必須有一個main包
import "fmt"
func main() {
var a int //宣告變數
fmt.Printf("請輸入變數a: ")
//阻塞等待用戶的輸入
//fmt.Scanf("%d", &a) //別忘了&
fmt.Scan(&a)
fmt.Println("a = ", a)
}
#執行結果:
請輸入變數e:666
a = 666
Scanf %d只能接收整型,不能接收字符型
所以在輸入字符型變數時應該使用fmt.Scanf(“%c”,&a)
| 格式 | 含義 |
|---|---|
| %% | 一個%字面量 |
| %b | 一個二進制整數值(基數為2),或者是一個(高級的)用科學計數法表示的指數為2的浮點數 |
| %c | 字符型,可以把輸入的數字按照ASCII碼相應轉換為對應的字符 |
| %d | 一個十進制數值(基數為10) |
| %f | 以標準記數法表示的浮點數或者復數值 |
| %o | 一個以八進制表示的數字(基數為8) |
| %p | 以十六進制(基數為16)表示的一個值的地址,前綴為0x,字母使用小寫的a-f表示 |
| %q | 使用Go語法以及必須時使用轉義,以雙引號括起來的字串或者位元組切片[]byte,或者是以單引號括起來的數字 |
| %s | 字串,輸出字串中的字符直至字串中的空字符(字串以'\0‘結尾,這個'\0'即空字符) |
| %t | 以true或者false輸出的布林值 |
| %T | 使用Go語法輸出的值的型別 |
| %x | 以十六進制表示的整型值(基數為十六),數字a-f使用小寫表示 |
| %X | 以十六進制表示的整型值(基數為十六),數字A-F使用小寫表示 |
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/229649.html
標籤:Go
