【Go語言學習筆記一】基礎語法

Go學習筆記

Go語言基礎語法

行分隔行

在 Go 程序中,一行表明一個語句結束。每一個語句不須要像 C 家族中的其它語言同樣以分號 ; 結尾,golang

可是可使用分號;結尾,若是當你將多個語句寫在同一行時,則必須使用分號;數據庫

1、變量

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
    }
} 

代碼說明:ide

  • 第3行,聲明一個整型類型的變量,能夠保存整數數值。函數

  • 第4行,聲明一個字符串類型的變量。post

  • 第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
}

2、常量

常量是恆定不變的值,例如圓周率。

常量的聲明與變量相似,只不過是使用 const 關鍵字。

常量能夠是字符、字符串、布爾值和數值。

常量不能用 := 語法聲明。

常量的聲明, 例如:

const pi = 3.1415926

注意:常量在聲明的時候必須賦值。

多個變量能夠一塊兒聲明,相似的,多個變量也能夠一塊兒聲明。例如:

const(
    pi = 3.1415926
    e = 2.718281
)

3、基本數據類型

Go語言中有豐富的數據類型,除了基本的整型、浮點型、布爾型、字符串外,還有切片、結構體、函數、map、通道(channel)等。

Go 語言的基本類型和其餘語言大同小異。

3.1 整型

整型能夠分紅如下兩個大類:

按長度分爲:int八、int1六、int3二、int64

對應的無符號整型:uint八、uint1六、uint3二、uint64

其中,uint8 就是咱們熟知的 byte 型.

3.2 浮點型

Go語言支持兩種浮點型數:

float3二、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。

4、數據類型的轉換

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、字符串應用

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 遍歷字符串 -- 獲取每一個字符串

兩種寫法

  1. 遍歷每一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

  

  1. 按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、枚舉

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、 類型別名

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()

9、條件語句

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 沒有三目運算符,因此不支持*?: 形式的條件判斷。

10、for循環

for 循環是一個循環控制結構,能夠執行指定次數的循環。

語法

Go 語言的 For 循環有 3 種形式,只有其中的一種使用分號。

和 C 語言的 for 同樣:

for init; condition; post { }

和 C 的 while 同樣:

for condition { }

和 C 的 for(;😉 同樣:

for { }
  • init: 通常爲賦值表達式,給控制變量賦初值;
  • condition: 關係表達式或邏輯表達式,循環控制條件;
  • post: 通常爲賦值表達式,給控制變量增量或減量。

for語句執行過程以下:

  • 一、先對錶達式 1 賦初值;
  • 二、判別賦值表達式 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、數組

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,以此類推。

img


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 第三行的第四個元素。

12、函數

函數是基本的代碼塊,用於執行一個任務。

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)
}

十3、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()
   //其餘操做
}

十4、輸入的使用

一、輸入的使用

第一種寫法: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使用小寫表示
相關文章
相關標籤/搜索