中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

1688運(yùn)營自學(xué)全套教程seo網(wǎng)站推廣工具

1688運(yùn)營自學(xué)全套教程,seo網(wǎng)站推廣工具,網(wǎng)站備案手機(jī)號碼,北京新冠疫情最新情況初見golang語法 package mainimport "fmt"func main() {/* 簡單的程序 萬能的hello world */fmt.Println("Hello Go")} 第一行代碼package main定義了包名。你必須在源文件中非注釋的第一行指明這個文件屬于哪個包,如:package main…

初見golang語法

  package mainimport "fmt"func main() {/* 簡單的程序 萬能的hello world */fmt.Println("Hello Go")}
  • 第一行代碼package main定義了包名。你必須在源文件中非注釋的第一行指明這個文件屬于哪個包,如:package main。package main表示一個可獨(dú)立執(zhí)行的程序,每個 Go 應(yīng)用程序都包含一個名為 main 的包
  • 下一行import "fmt"告訴 Go 編譯器這個程序需要使用 fmt 包(的函數(shù),或其他元素),fmt 包實(shí)現(xiàn)了格式化 IO(輸入/輸出)的函數(shù)

  • 下一行func main()是程序開始執(zhí)行的函數(shù)。main 函數(shù)是每一個可執(zhí)行程序所必須包含的,一般來說都是在啟動后第一個執(zhí)行的函數(shù)(如果有 init() 函數(shù)則會先執(zhí)行該函數(shù))

注意:這里面go語言的語法,定義函數(shù)的時候,‘{’ 必須和函數(shù)名在同一行,不能另起一行

變量聲明

單獨(dú)變量聲明

第一種,指定變量類型,聲明后若不賦值,使用默認(rèn)值0

var a int
fmt.Printf(" = %d\n", a)

第二種,根據(jù)值自行進(jìn)行判斷變量類型

package mainimport ("fmt""reflect"
)func main() {var a = "abc"fmt.Println("a的類型是:", reflect.TypeOf(a))
}

第三種,省略var, 注意 :=左側(cè)的變量不應(yīng)該是已經(jīng)聲明過的,否則會導(dǎo)致編譯錯誤

a := 10
b := "hello"var c int
c := 20 // 這里會報錯,因?yàn)?`c` 已經(jīng)聲明過了

總結(jié)

package mainimport "fmt"func main() {//第一種 使用默認(rèn)值var a intfmt.Printf("a = %d\n", a)//第二種var b int = 10fmt.Printf("b = %d\n", b)//第三種 省略后面的數(shù)據(jù)類型,自動匹配類型var c = 20fmt.Printf("c = %d\n", c)//第四種 省略var關(guān)鍵字d := 3.14fmt.Printf("d = %f\n", d)
}

多變量聲明

package mainimport "fmt"var x, y int
var ( //這種分解的寫法,一般用于聲明全局變量a intb bool
)var c, d int = 1, 2
var e, f = 123, "liudanbing"//這種不帶聲明格式的只能在函數(shù)體內(nèi)聲明
//g, h := 123, "需要在func函數(shù)體內(nèi)實(shí)現(xiàn)"func main() {g, h := 123, "需要在func函數(shù)體內(nèi)實(shí)現(xiàn)"fmt.Println(x, y, a, b, c, d, e, f, g, h)//不能對g變量再次做初始化聲明//g := 400_, value := 7, 5  //實(shí)際上7的賦值被廢棄,變量 _  不具備讀特性//fmt.Println(_) //_變量的是讀不出來的fmt.Println(value) //5
}

常量?

基本使用

常量是一個簡單值的標(biāo)識符,在程序運(yùn)行時,不會被修改的量。

常量中的數(shù)據(jù)類型只可以是布爾型、數(shù)字型(整數(shù)型、浮點(diǎn)型和復(fù)數(shù))和字符串型。

  • 常量的定義格式:?const identifier [type] = value
    • 顯示定義:const b string = "abc"
    • 隱式定義:const b = "abc"

例如:

package mainimport "fmt"func main() {const LENGTH int = 10const WIDTH int = 5   var area intconst a, b, c = 1, false, "str" //多重賦值area = LENGTH * WIDTHfmt.Printf("面積為 : %d\n", area)println(a, b, c)   
}//運(yùn)行結(jié)果
面積為 : 50
1 false str

常量聲明枚舉

在 Go 語言中沒有直接的枚舉類型,但是我們可以可以定義一組常量來表示枚舉值

const (Unknown = 0Female = 1Male = 2
)
// 數(shù)字 0、1 和 2 分別代表未知性別、女性和男性

常量可以用len(), cap(), unsafe.Sizeof()常量計(jì)算表達(dá)式的值。常量表達(dá)式中,函數(shù)必須是內(nèi)置函數(shù),否則編譯不過:

package mainimport "unsafe"
const (a = "abc"b = len(a)c = unsafe.Sizeof(a)
)func main(){println(a, b, c)
}

iota標(biāo)識符

在我們定義一些常量的時候,可能需要給它們進(jìn)行賦值。在Go語言當(dāng)中,就可以簡化這個賦值操作通過iota標(biāo)示符,如:

package mainimport "fmt"const (Sunday = iotaMondayTuesdayWednesdayThursdayFridaySaturday
)func main() {today := Mondayfmt.Println("Today is:", today)
}

iota不僅僅用于自增,還可以根據(jù)定義一些百搭是,來進(jìn)行賦值操作,如:

const (d = iota * 2ef
)func main() {fmt.Println(d) // 0fmt.Println(e) // 2fmt.Println(f) // 4
}

函數(shù)

函數(shù)返回多個值

Go的函數(shù)可以返回多個值,例如:

package mainimport "fmt"func swap(x, y string) (string, string) {return y, x
}
func main() {a, b := swap("a", "b")fmt.Println(a, " ", b)
}//執(zhí)行結(jié)果:b   a

init函數(shù)和import

init 函數(shù)可在package main中,可在其他package中,可在同一個package中出現(xiàn)多次,而main 函數(shù)只能在package main中

執(zhí)行順序

golang里面保留了兩個函數(shù):init函數(shù)(能應(yīng)用于所有的package)和main函數(shù)(只能應(yīng)用于package main)。這兩個函數(shù)在定義的時候不能有任何參數(shù)和返回值

雖然一個package里面可以寫任意多個init函數(shù),但這無論是對于可讀性還是以后的可維護(hù)性來說,我們都強(qiáng)烈建議用戶在一個package中每個文件只寫一個init函數(shù)。go程序會自動調(diào)用init()和main(),所以你不需要在任何地方調(diào)用這兩個函數(shù)。每個package中的init函數(shù)都是可選的,但package main就必須包含一個main函數(shù)

程序的初始化和執(zhí)行都起始于main包。如果main包還導(dǎo)入了其它的包,那么就會在編譯時將它們依次導(dǎo)入。有時一個包會被多個包同時導(dǎo)入,那么它只會被導(dǎo)入一次(例如很多包可能都會用到fmt包,但它只會被導(dǎo)入一次,因?yàn)闆]有必要導(dǎo)入多次)。當(dāng)一個包被導(dǎo)入時,如果該包還導(dǎo)入了其它的包,那么會先將其它包導(dǎo)入進(jìn)來,然后再對這些包中的包級常量和變量進(jìn)行初始化,接著執(zhí)行init函數(shù)(如果有的話),依次類推。等所有被導(dǎo)入的包都加載完畢了,就會開始對main包中的包級常量和變量進(jìn)行初始化,然后執(zhí)行main包中的init函數(shù)(如果存在的話),最后執(zhí)行main函數(shù)。下圖詳細(xì)地解釋了整個執(zhí)行過程:

代碼示例:

package InitLib1import "fmt"func init() {fmt.Println("lib1")
}package InitLib2import "fmt"func init() {fmt.Println("lib2")
}package mainimport ("fmt"_ "GolangTraining/InitLib1"_ "GolangTraining/InitLib2"
)func init() {fmt.Println("libmain init")
}func main() {fmt.Println("libmian main")
}//執(zhí)行結(jié)果:
lib1
lib2
libmain init
libmian main

輸出的順序與我們上面圖給出的順序是一致的。那我們現(xiàn)在就改動一個地方,Lib1包導(dǎo)入Lib2,main包不管:

package InitLib1import ("fmt"_ "GolangTraining/InitLib2"
)func init() {fmt.Println("lib1")
}//輸出結(jié)果:
lib2
lib1
libmain init
libmian main

main包以及Lib1包都導(dǎo)入了Lib2,但是只出現(xiàn)一次,并且最先輸出,說明如果一個包會被多個包同時導(dǎo)入,那么它只會被導(dǎo)入一次,而先輸出lib2是因?yàn)閙ain包中導(dǎo)入Lib1時,Lib1又導(dǎo)入了Lib2,會首先初始化Lib2包的東西

注意:如果需要將當(dāng)前的包函數(shù)提供給外部,需要將函數(shù)名首字母大寫!!!否則會引用不了!!!

函數(shù)參數(shù)

函數(shù)的參數(shù)在傳遞的時候主要是分為兩種類型:值傳遞指針傳遞

值傳遞:值傳遞是指在調(diào)用函數(shù)時將實(shí)際參數(shù)復(fù)制一份傳遞到函數(shù)中,這樣在函數(shù)中如果對參數(shù)進(jìn)行修改,將不會影響到實(shí)際參數(shù)

/* 定義相互交換值的函數(shù) */
func swap(x, y int) int {var temp inttemp = x /* 保存 x 的值 */x = y    /* 將 y 值賦給 x */y = temp /* 將 temp 值賦給 y*/return temp;
}

指針傳遞:指針傳遞是指在調(diào)用函數(shù)時將實(shí)際參數(shù)的地址傳遞到函數(shù)中,那么在函數(shù)中對參數(shù)所進(jìn)行的修改,將影響到實(shí)際參數(shù)

/* 定義交換值函數(shù)*/
func swap(x *int, y *int) {var temp inttemp = *x    /* 保持 x 地址上的值 */*x = *y      /* 將 y 值賦給 x */*y = temp    /* 將 temp 值賦給 y */
}

defer

defer類似于我們Java中的finally,它會在我們程序執(zhí)行的最后執(zhí)行一些任務(wù)defer語句被用于預(yù)定對一個函數(shù)的調(diào)用??梢园堰@類被defer語句調(diào)用的函數(shù)稱為延遲函數(shù)。

defer作用:

  • 釋放占用的資源
  • 捕捉處理異常
  • 輸出日志

如果一個函數(shù)中有多個defer語句,它們會以LIFO(后進(jìn)先出)的順序執(zhí)行:

func Demo(){defer fmt.Println("1")defer fmt.Println("2")defer fmt.Println("3")defer fmt.Println("4")
}
func main() {Demo()
}//運(yùn)行結(jié)果:4 3 2 1

panic和recover

panic(宕機(jī)) 和 recover(恢復(fù))是Go語言的兩個內(nèi)置函數(shù),這兩個內(nèi)置函數(shù)用來處理Go的運(yùn)行時錯誤(runtime errors)。panic 用來主動拋出異常,recover用來捕獲panic拋出的異常

引發(fā)panic有兩種情況:一種是程序主動調(diào)用panic()函數(shù),另一種是程序產(chǎn)生運(yùn)行時錯誤,由運(yùn)行時檢測并拋出。例如:

示例1:程序主動調(diào)用panic,觸發(fā)宕機(jī),讓程序崩潰

func funcA() {fmt.Println("func A")
}func funcB() {panic("panic in B")
}func funcC() {fmt.Println("func C")
}
func main() {funcA()funcB()funcC()
}
運(yùn)行結(jié)果:func A
panic: panic in Bgoroutine 1 [running]:
main.funcB(...)/home/wangxm/go_work/src/chapter05/demo.go:12
main.main()/home/wangxm/go_work/src/chapter05/demo.go:20 +0x96
exit status 2

當(dāng)在funcB中主動調(diào)用了panic 函數(shù)后,程序發(fā)生宕機(jī)直接退出了,同時輸出了堆棧和goroutine相關(guān)信息,這讓我們可以看到錯誤發(fā)生的位置。當(dāng)panic()觸發(fā)的宕機(jī)發(fā)生時,panic后面的代碼將不會被執(zhí)行,但是在panic()函數(shù)前面的已經(jīng)執(zhí)行過的defer語句依然會在宕機(jī)發(fā)生時執(zhí)行defer中的延遲函數(shù)。

示例2:在宕機(jī)時觸發(fā)defer語句延遲函數(shù)的執(zhí)行:

func funcA() {fmt.Println("func A")
}func funcB() {panic("panic in B")
}func funcC() {fmt.Println("func C")
}func funcD() {fmt.Println("func D")
}func main() {defer funcA()defer funcC()fmt.Println("this is main")funcB()defer funcD()
}
運(yùn)行結(jié)果:this is main
func C
func A
panic: panic in Bgoroutine 1 [running]:
main.funcB(...)/home/wangxm/go_work/src/chapter05/demo.go:12
main.main()/home/wangxm/go_work/src/chapter05/demo.go:29 +0xca
exit status 2

從運(yùn)行結(jié)果可以看出,當(dāng)程序流程正常執(zhí)行到funcB()函數(shù)的panic語句時,在panic()函數(shù)被執(zhí)行前,defer語句會優(yōu)先被執(zhí)行,defer語句的執(zhí)行順序是先進(jìn)后出,所以funcC()延遲函數(shù)先執(zhí)行,funcA()后執(zhí)行,當(dāng)所有已注冊的defer語句都執(zhí)行完畢,才會執(zhí)行panic()函數(shù),觸發(fā)宕機(jī),程序崩潰退出,因此程序流程執(zhí)行不到funcD()函數(shù)。

發(fā)生panic后,程序會從調(diào)用panic的函數(shù)位置或發(fā)生panic的地方立即返回,逐層向上執(zhí)行函數(shù)的defer語句,然后逐層打印函數(shù)調(diào)用堆棧信息,直到被recover捕獲或運(yùn)行到最外層函數(shù)而退出。如本例中,程序從funcB()函數(shù)返回到上層的main()函數(shù)中,然后執(zhí)行已注冊的defer語句的延遲函數(shù),最后從main函數(shù)中退出,并且打印了退出狀態(tài)碼的值為2

recover()函數(shù)用來捕獲或者說是攔截panic的,阻止panic繼續(xù)向上層傳遞。無論是主動調(diào)用panic()函數(shù)觸發(fā)的宕機(jī)還是程序在運(yùn)行過程中由Runtime層拋出的異常,都可以配合defer 和 recover 實(shí)現(xiàn)異常捕獲和恢復(fù),讓代碼在發(fā)生panic后能夠繼續(xù)執(zhí)行

Go語言沒有異常系統(tǒng),其使用panic觸發(fā)宕機(jī)類似于其他語言的拋出異常,而recover的宕機(jī)恢復(fù)機(jī)制就對應(yīng)try...catch機(jī)制

示例:使用recover捕獲panic異常,恢復(fù)程序的運(yùn)行:

func funcA() {fmt.Println("func A")
}func funcB() {defer func(){//捕獲panic,并恢復(fù)程序使其繼續(xù)運(yùn)行if err := recover(); err != nil {fmt.Println("recover in funcB")}}()panic("panic in B")  //主動拋出異常
}func funcC() {fmt.Println("func C")
}func funcD() {fmt.Println("func D")
}func main() {defer funcA()defer funcC()fmt.Println("this is main")funcB()defer funcD()
}運(yùn)行結(jié)果:this is main
recover in funcB
func D
func C
func A

當(dāng)recover捕獲到panic時,不會造成整個進(jìn)程的崩潰,它會從觸發(fā)panic的位置退出當(dāng)前函數(shù),然后繼續(xù)執(zhí)行后續(xù)代碼

IF判斷

在Go語言中,if語句用于條件判斷,它有以下幾種常見的用法和特點(diǎn):

基本用法

  • 語法結(jié)構(gòu)
    if condition {// 當(dāng)條件為真時執(zhí)行的代碼塊
    }
    
    其中condition是一個布爾表達(dá)式,如果condition的值為true,則執(zhí)行花括號內(nèi)的代碼塊。
  • 示例
    num := 10
    if num > 5 {fmt.Println("num大于5")
    }
    

帶有else子句

  • 語法結(jié)構(gòu)
    if condition {// 當(dāng)條件為真時執(zhí)行的代碼塊
    } else {// 當(dāng)條件為假時執(zhí)行的代碼塊
    }
    
  • 示例
    num := 3
    if num > 5 {fmt.Println("num大于5")
    } else {fmt.Println("num小于等于5")
    }
    

帶有else if子句

  • 語法結(jié)構(gòu)
    if condition1 {// 當(dāng)條件1為真時執(zhí)行的代碼塊
    } else if condition2 {// 當(dāng)條件2為真時執(zhí)行的代碼塊
    } else {// 當(dāng)條件1和條件2都為假時執(zhí)行的代碼塊
    }
    
  • 示例
    num := 7
    if num > 10 {fmt.Println("num大于10")
    } else if num > 5 {fmt.Println("num大于5且小于等于10")
    } else {fmt.Println("num小于等于5")
    }
    

if語句中聲明和初始化變量

  • 語法結(jié)構(gòu)
    可以在if語句的條件判斷部分同時聲明和初始化一個變量,這個變量的作用域僅限于if語句及其相關(guān)的elseelse if子句
    if var_declaration := expression; condition {// 當(dāng)條件為真時執(zhí)行的代碼塊,且可以使用var_declaration變量
    }
    
  • 示例
    if num := 8; num > 5 {fmt.Println("num大于5,num的值為:", num)
    }
    
    在這個例子中,numif語句中被聲明和初始化,并且只能在if相關(guān)的代碼塊中使用。如果numif語句外已經(jīng)存在,那么在if語句中使用這種方式聲明num會導(dǎo)致編譯錯誤,因?yàn)?code>if語句中這種方式的變量聲明會被視為一個新的局部變量聲明

循環(huán)

在Go語言中,有兩種主要的循環(huán)結(jié)構(gòu):for循環(huán)和range循環(huán)(range可以看作是一種特殊的基于for循環(huán)的便利形式,用于迭代容器類型的數(shù)據(jù))。

for循環(huán)

  1. 基本for循環(huán)

    • 語法結(jié)構(gòu)
      for initialization; condition; post {// 循環(huán)體
      }
      
      • initialization:循環(huán)開始前的初始化操作,通常用于聲明和初始化循環(huán)變量。
      • condition:循環(huán)的條件判斷,只要該條件為true,循環(huán)就會繼續(xù)執(zhí)行。
      • post:每次循環(huán)結(jié)束后執(zhí)行的操作,通常用于更新循環(huán)變量。
    • 示例
      for i := 0; i < 5; i++ {fmt.Println(i)
      }
      
      這個循環(huán)會從i = 0開始,只要i < 5就會執(zhí)行循環(huán)體,每次循環(huán)結(jié)束后i的值會增加1,最終會打印出04這幾個數(shù)字。

range循環(huán)

  1. 用于迭代數(shù)組和切片

    • 語法結(jié)構(gòu)
      for index, value := range arrayOrSlice {// 對索引和值進(jìn)行處理
      }
      
      其中index是數(shù)組或切片元素的索引,value是元素的值。對于每個元素,循環(huán)都會執(zhí)行一次。
    • 示例
      arr := []int{1, 2, 3, 4, 5}
      for index, value := range arr {fmt.Printf("索引為 %d 的元素值為 %d\n", index, value)
      }
      
      這個循環(huán)會遍歷切片arr,并打印出每個元素的索引和值。
  2. 用于迭代字符串

    • 字符串在Go語言中可以看作是一個字節(jié)數(shù)組,所以也可以用range循環(huán)來迭代。
    • 語法結(jié)構(gòu)
      for index, value := range stringValue {// 對索引和值進(jìn)行處理// 需要注意的是,這里的價值可能是一個字節(jié)(對于ASCII字符)或者是一個Unicode碼點(diǎn)的第一個字節(jié)(對于非ASCII字符)// 如果要獲取完整的Unicode碼點(diǎn),需要進(jìn)一步處理
      }
      
    • 示例
      str := "hello"
      for index, value := range str {fmt.Printf("索引為 %d 的字符值為 %c\n", index, rune(value))
      }
      
      這里使用rune函數(shù)將字節(jié)值轉(zhuǎn)換為Unicode碼點(diǎn)對應(yīng)的字符,以便正確打印出字符串中的字符。
  3. 用于迭代映射(map)

    • 語法結(jié)構(gòu)
      for key, value := range mapValue {// 對鍵和值進(jìn)行處理
      }
      
      其中key是映射的鍵,value是對應(yīng)鍵的值。對于每個鍵值對,循環(huán)都會執(zhí)行一次。
    • 示例
      m := map[string]int{"a": 1, "b": 2, "c": 3}
      for key, value := range m {fmt.Printf("鍵為 %s 的值為 %d\n", key, value)
      }
      
      這個循環(huán)會遍歷映射m,并打印出每個鍵值對的鍵和值。

集合

集合分為slice和map兩種,其中slice是數(shù)組的抽象。

slice

slice是數(shù)組的抽象,Go 數(shù)組的長度不可改變,在特定場景中這樣的集合就不太適用,Go中提供了一種靈活,功能強(qiáng)悍的內(nèi)置類型切片("動態(tài)數(shù)組"),與數(shù)組相比切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大

方式一:聲明一個未指定大小的數(shù)組來定義切片

var identifier []type

方式二:使用make()函數(shù)來創(chuàng)建切片

var slice1 []type = make([]type, len)
也可以簡寫為
slice1 := make([]type, len)//也可以指定容量,其中capacity為可選參數(shù)
make([]T, length, capacity)

?make函數(shù)參數(shù)說明

  • length
    • 表示切片初始的長度,即切片中元素的個數(shù)。這個值決定了切片創(chuàng)建后可以直接訪問的元素范圍。例如,如果length3,那么可以通過切片索引0、1、2來訪問元素
  • capacity
    • 表示切片的容量,它是切片底層數(shù)組的大小。切片的容量必須大于等于長度。容量決定了切片在不重新分配內(nèi)存的情況下能夠擴(kuò)展的最大程度。例如,如果capacity5,長度為3,那么在不重新分配內(nèi)存的情況下,切片可以通過append操作最多再容納2個元素

操作方法:

append函數(shù)

newSlice := append(slice, elements...)

其中slice是原始切片,elements是要添加的一個或多個元素。append函數(shù)會返回一個新的切片,這個新切片包含了原始切片的所有元素以及新添加的元素

copy函數(shù)

/* 拷貝 numbers 的內(nèi)容到 numbers1 */copy(numbers1,numbers)

len函數(shù)

//獲取切片長度
len(slice)

cap函數(shù)

//獲取切片容量
cap(slice)

切片截取:可以通過設(shè)置下限及上限來設(shè)置截取切片[lower-bound:upper-bound]

package mainimport "fmt"func main() {/* 創(chuàng)建切片 */numbers := []int{0, 1, 2, 3, 4, 5, 6, 7, 8}printSlice(numbers)/* 打印原始切片 */fmt.Println("numbers ==", numbers)/* 打印子切片從索引1(包含) 到索引4(不包含)*/fmt.Println("numbers[1:4] ==", numbers[1:4])/* 默認(rèn)下限為 0*/fmt.Println("numbers[:3] ==", numbers[:3])/* 默認(rèn)上限為 len(s)*/fmt.Println("numbers[4:] ==", numbers[4:])numbers1 := make([]int, 0, 5)printSlice(numbers1)/* 打印子切片從索引  0(包含) 到索引 2(不包含) */number2 := numbers[:2]printSlice(number2)/* 打印子切片從索引 2(包含) 到索引 5(不包含) */number3 := numbers[2:5]printSlice(number3)}func printSlice(x []int) {fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x)
}

運(yùn)行結(jié)果:

len=9 cap=9 slice=[0 1 2 3 4 5 6 7 8]
numbers == [0 1 2 3 4 5 6 7 8]
numbers[1:4] == [1 2 3]
numbers[:3] == [0 1 2]
numbers[4:] == [4 5 6 7 8]
len=0 cap=5 slice=[]
len=2 cap=9 slice=[0 1]
len=3 cap=7 slice=[2 3 4]

map

映射(map)是Go語言中一種用于存儲鍵值對的數(shù)據(jù)結(jié)構(gòu)。以下是一些常見的map操作方法:

1. 創(chuàng)建map

  • 可以使用make函數(shù)創(chuàng)建map,語法為make(map[KeyType]ValueType),其中KeyType是鍵的類型,ValueType是值的類型。例如m := make(map[string]int)創(chuàng)建了一個鍵為字符串類型,值為整數(shù)類型的map。

2. 插入鍵值對

  • 可以直接給map賦值來插入鍵值對。例如m := make(map[string]int); m["key1"] = 1,這里將鍵為"key1",值為1的鍵值對插入到map中。

3. 訪問鍵值對

  • 使用鍵來訪問map中的值。例如m := make(map[string]int); m["key1"] = 1; fmt.Println(m["key1"])會打印出鍵為"key1"的值1。
  • 如果訪問的鍵不存在于map中,會返回值類型的零值。例如m := make(map[string]int); fmt.Println(m["nonexistent_key"])會打印出整數(shù)類型的零值0

4. 修改鍵值對

  • 可以使用鍵來修改map中的值。例如m := make(map[string]int); m["key1"] = 1; m["key1"] = 2; fmt.Println(m["key1"])會將鍵為"key1"的值從1修改為2

5. 刪除鍵值對

  • 使用delete函數(shù)來刪除鍵值對,語法為delete(map, key),其中map是要操作的map,key是要刪除的鍵。例如m := make(map[string]int); m["key1"] = 1; delete(m, "key1"); fmt.Println(m["key1"])會刪除鍵為"key1"的值,并返回整數(shù)類型的零值0,因?yàn)樵撴I值對已經(jīng)被刪除。

6. 檢查鍵是否存在

  • 可以使用一種特殊的語法來檢查鍵是否存在于map中,同時獲取對應(yīng)的值。例如m := make(map[string]int); m["key1"] = 1; value, exists := m["key1"]; fmt.Println(value, exists)會打印出1 true,因?yàn)殒I"key1"存在于map中,并且對應(yīng)的值為1。如果鍵不存在,exists會返回falsevalue會返回值類型的零值。

7. 遍歷map

  • 使用range來遍歷map,會依次獲取map中的鍵值對。例如m := make(map[string]int); m["key1"] = 1; m["ive had no joy with maps in GoLang!": "Here is an example of a text that could be inserted into a map, though it might not be a very practical one"]; for key, value := range m { fmt.Println(key, value) }會遍歷map中的鍵值對并打印出來。

8. map的長度

  • 使用len函數(shù)可以獲取map的長度,即map中鍵值對的個數(shù)。例如m := make(map[string]int); m["key1"] = 1; m["key2"] = 2; fmt.Println(len(m))會打印出2,因?yàn)檫@個map中有兩個鍵值對

結(jié)構(gòu)體

在 Go 語言中,結(jié)構(gòu)體(struct)是一種復(fù)合數(shù)據(jù)類型,它允許用戶將不同類型的數(shù)據(jù)組合在一起,形成一個新的類型。以下是關(guān)于結(jié)構(gòu)體的詳細(xì)介紹:

結(jié)構(gòu)體的定義

結(jié)構(gòu)體的定義一個是使用struct關(guān)鍵字,基礎(chǔ)語法如下:

type StructName struct {Field1 Type1Field2 Type2//...
}

其中,type是關(guān)鍵字用于定義新的類型,StructName是結(jié)構(gòu)體的名稱,struct是結(jié)構(gòu)體的關(guān)鍵字,后面跟著大括號,大括號內(nèi)是結(jié)構(gòu)體的各個字段(field),每個字段由字段名和字段類型組成。例如:

type Person struct {Name stringAge  int
}

定義了一個名為Person的結(jié)構(gòu)體,它包含兩個字段:Name(字符串類型)和Age(整數(shù)類型)

結(jié)構(gòu)體變量的創(chuàng)建和初始化

  • 方法一:逐個字段初始化
    可以通過結(jié)構(gòu)體類型創(chuàng)建結(jié)構(gòu)體變量,并逐個初始化結(jié)構(gòu)體的字段。例如:
var p Person
p.Name = "Alice"
p.Age = 25
  • 方法二:使用結(jié)構(gòu)體字面量初始化
    使用結(jié)構(gòu)體字面量可以在創(chuàng)建結(jié)構(gòu)體變量的同時初始化結(jié)構(gòu)體的字段。有兩種形式:
  • 按字段順序初始化
p := Person{"Bob", 30}

這種方式要求按照結(jié)構(gòu)體定義時字段的順序提供值。

  • 指定字段名初始化
p := Person{Name: "Charlie", Age: 35}

這種方式可以不按照結(jié)構(gòu)體定義時字段的順序提供值,只要指定正確的字段名和值即可。

結(jié)構(gòu)體的嵌套

  • 結(jié)構(gòu)體可以嵌套其他結(jié)構(gòu)體。例如:
type Address struct {City    stringStreet  stringZipCode int
}type Employee struct {PersonJobTitle  stringAddress   AddressSalary    int
}

這里定義了Address結(jié)構(gòu)體和Employee結(jié)構(gòu)體,Employee結(jié)構(gòu)體嵌套了Person結(jié)構(gòu)體和Address結(jié)構(gòu)體。當(dāng)訪問嵌套結(jié)構(gòu)體的字段時,可以使用.操作符進(jìn)行多級訪問。例如:e := Employee{Person{"David", 40}, "Engineer", Address{"New York", "5th Avenue", 10001}, 80000}; fmt.Println(e.Person.Name)會打印出David

結(jié)構(gòu)體方法

  • 可以為結(jié)構(gòu)體定義方法,結(jié)構(gòu)體方法類似于面向?qū)ο笳Z言中的類方法。結(jié)構(gòu)體方法的定義語法如下:
func (s StructName) MethodName() ReturnType {// 方法體
}

其中,(s StructName)部分稱為接收者(receiver),它表示該方法是屬于StructName結(jié)構(gòu)體的,s是接收者變量,可以在方法體中使用接收者變量來訪問結(jié)構(gòu)體的相關(guān)字段。例如:

func (p Person) GetName() string {return p.Name
}

定義了一個Person結(jié)構(gòu)體的方法GetName,它返回Person結(jié)構(gòu)體的Name字段的值。

結(jié)構(gòu)體的內(nèi)存布局

  • 結(jié)構(gòu)體在內(nèi)存中的布局是按照字段定義的順序依次排列的,每個字段占用一定的內(nèi)存空間。不同類型的字段在內(nèi)存中所占的空間大小不同,例如,整數(shù)類型通常占用4個字節(jié)(在32位系統(tǒng)中)或8個字節(jié)(在62位系統(tǒng)中),字符串類型的內(nèi)存占用則比較復(fù)雜,它包含一個指針和一些其他信息。
  • 當(dāng)結(jié)構(gòu)體嵌套其他結(jié)構(gòu)體時,嵌套的結(jié)構(gòu)體的內(nèi)存空間也是按照其自身的字段定義順序依次排列在主結(jié)構(gòu)體的內(nèi)存空間內(nèi)。

結(jié)構(gòu)體的比較

  • 如果結(jié)構(gòu)體的所有字段都是可比較的,那么結(jié)構(gòu)體本身也是可比較的。比較兩個結(jié)構(gòu)體時,會逐個比較結(jié)構(gòu)體的各個字段。例如:
p1 := Person{"Alice", 25}
p2 := Person{"Alice", 25}
if p1 == p2 {fmt.Println("p1和p2相等")
}

如果結(jié)構(gòu)體中有不可比較的字段(如切片、映射等),那么結(jié)構(gòu)體本身不可比較

接口

接口定義

  • 首先我們定義了一個接口Shape
type Shape interface {Area() float64
}

這個接口規(guī)定了任何實(shí)現(xiàn)它的類型都必須有一個Area方法,該方法沒有參數(shù)并且返回一個float64類型的值。這就像是一個合同,規(guī)定了實(shí)現(xiàn)這個接口的類型需要具備計(jì)算面積的能力。

接口實(shí)現(xiàn)

  • 然后我們有一個Rectangle結(jié)構(gòu)體:
type Rectangle struct {length float64width  float64
}

并且為這個結(jié)構(gòu)體定義了一個Area方法:

func (r Rectangle) Area() float64 {return r.length * r.width
}

通過定義這個Area方法,Rectangle結(jié)構(gòu)體滿足了Shape接口的要求,也就是說Rectangle結(jié)構(gòu)體實(shí)現(xiàn)了Shape接口。這就好比Rectangle結(jié)構(gòu)體簽署了Shape接口這個合同,它具備了按照合同要求計(jì)算面積的能力。

接口使用

  • 作為函數(shù)參數(shù):我們定義了一個函數(shù)CalculateArea
func CalculateArea(s Shape) float64 {return s.Area()
}

在這個函數(shù)中,參數(shù)sShape接口類型。這意味著我們可以傳入任何實(shí)現(xiàn)了Shape接口的類型的值作為參數(shù)。當(dāng)我們調(diào)用這個函數(shù)時,如果傳入的是Rectangle結(jié)構(gòu)體的值(因?yàn)?code>Rectangle實(shí)現(xiàn)了Shape接口),那么在函數(shù)內(nèi)部就會調(diào)用Rectangle結(jié)構(gòu)體的Area方法來計(jì)算面積。

  • 作為變量類型:我們還可以定義一個Shape接口類型的變量s
var s Shape
r := Rectangle{length: 5, width: 3}
s = r
fmt.Println(s.Area())

這里首先定義了一個Shape接口類型的變量s,然后創(chuàng)建了一個Rectangle結(jié)構(gòu)體的值r,并將r賦值給s。因?yàn)?code>Rectangle實(shí)現(xiàn)了Shape接口,所以這種賦值是合法的。最后我們可以通過s調(diào)用Area方法來計(jì)算面積,實(shí)際上是調(diào)用了Rectangle結(jié)構(gòu)體的Area方法。

這樣通過接口,我們可以實(shí)現(xiàn)不同類型之間的通用性和多態(tài)性,使得代碼更加靈活和可維護(hù)。例如,如果我們還有一個Square結(jié)構(gòu)體也實(shí)現(xiàn)了Shape接口,那么我們可以同樣使用CalculateArea函數(shù)來計(jì)算它的面積,而不需要為Square重新定義一個計(jì)算面積的函數(shù)。

面向?qū)ο蟮奶匦?/h3>

Go 語言雖然不是純粹的面向?qū)ο缶幊陶Z言,但它支持一些面向?qū)ο蟮奶匦?#xff0c;主要包括封裝、繼承和多態(tài),以下是具體介紹:

封裝性

定義:封裝是指將數(shù)據(jù)和操作數(shù)據(jù)的方法組合在一起,并對外部隱藏數(shù)據(jù)的實(shí)現(xiàn)細(xì)節(jié),只提供必要的接口來訪問和操作數(shù)據(jù)

實(shí)現(xiàn)方式:通過結(jié)構(gòu)體和方法實(shí)現(xiàn),結(jié)構(gòu)體用于定義數(shù)據(jù)結(jié)構(gòu),將相關(guān)的數(shù)據(jù)組合在一起。例如,定義一個Rectangle結(jié)構(gòu)體來表示矩形的長和寬:

type Rectangle struct {length float64width float64
}

方法用于操作結(jié)構(gòu)體中的數(shù)據(jù)。例如,為Rectangle結(jié)構(gòu)體定義一個計(jì)算面積的方法:

func (r Rectangle) Area() float64 {return r.length * r.width
}

通過這種方式,Rectangle結(jié)構(gòu)體的內(nèi)部數(shù)據(jù)(長和寬)被封裝起來,外部只能通過Area方法來獲取矩形的面積,而無法直接訪問長和寬的數(shù)據(jù)

看下面的例子會更加清晰:

package mainimport "fmt"//定義一個結(jié)構(gòu)體
type T struct {name string
}func (t T) method1() {t.name = "new name1"
}func (t *T) method2() {t.name = "new name2"
}func main() {t := T{"old name"}fmt.Println("method1 調(diào)用前 ", t.name)t.method1()fmt.Println("method1 調(diào)用后 ", t.name)fmt.Println("method2 調(diào)用前 ", t.name)t.method2()fmt.Println("method2 調(diào)用后 ", t.name)
}

運(yùn)行結(jié)果:

method1 調(diào)用前  old name
method1 調(diào)用后  old name
method2 調(diào)用前  old name
method2 調(diào)用后  new name2

當(dāng)調(diào)用t.method1()時相當(dāng)于method1(t),實(shí)參和行參都是類型 T,可以接受。此時在method1()中的t只是參數(shù)t的值拷貝,所以method1()的修改影響不到main中的t變量。

當(dāng)調(diào)用t.method2()=>method2(t),這是將 T 類型傳給了 *T 類型,go可能會取 t 的地址傳進(jìn)去:method2(&t)。所以 method1() 的修改可以影響 t。

所以說下面的代碼保證了封裝性:

func (t T) method1() {t.name = "new name1"
}

繼承

在Go語言中,雖然沒有像傳統(tǒng)面向?qū)ο笳Z言中那樣的類繼承機(jī)制,但可以通過結(jié)構(gòu)體嵌套實(shí)現(xiàn)類似繼承的效果。以下是詳細(xì)說明:

基本概念

  • 繼承是一種機(jī)制,它允許一個類型(子類或派生類)繼承另一個類型(父類或基類)的屬性和方法,從而實(shí)現(xiàn)代碼的復(fù)用和擴(kuò)展。子類可以在繼承父類的基礎(chǔ)上添加自己的特性,并且可以重寫父類的某些方法以滿足自身的需求。

Go語言中的實(shí)現(xiàn)方式 - 結(jié)構(gòu)體嵌套

  • 假設(shè)我們有一個Base結(jié)構(gòu)體代表基類,它具有一些屬性和方法。例如:
type Base struct {Property1 stringProperty2 int
}func (b Base) Method1() {// 基類方法的實(shí)現(xiàn)
}
  • 現(xiàn)在我們想要創(chuàng)建一個Derived結(jié)構(gòu)體來繼承Base結(jié)構(gòu)體的特性。我們可以通過結(jié)構(gòu)體嵌套來實(shí)現(xiàn):
type Derived struct {BaseAdditionalProperty string
}
  • 通過這種嵌套方式,Derived結(jié)構(gòu)體繼承了Base結(jié)構(gòu)體的所有屬性和方法。例如,Derived結(jié)構(gòu)體可以直接訪問Base結(jié)構(gòu)體的Property1Property2屬性,并且可以調(diào)用Base結(jié)構(gòu)體的Method1方法。

方法重寫(覆蓋)

  • 在Go語言中,雖然沒有嚴(yán)格的方法重寫語法,但通過結(jié)構(gòu)體嵌套和方法定義,可以實(shí)現(xiàn)類似的效果。
  • 假設(shè)我們想要在Derived結(jié)構(gòu)體中重寫Base結(jié)構(gòu)體的Method1方法。我們可以在Derived結(jié)構(gòu)體中重新定義一個Method1方法:
func (d Derived) Method1() {// 新的方法實(shí)現(xiàn),可能會調(diào)用原始Base結(jié)構(gòu)體的方法或者完全替代它// 例如,可以先調(diào)用原始Base結(jié)構(gòu)體的方法,然后再添加一些額外的操作d.Base.Method1()// 其他額外操作
}
  • 這樣,當(dāng)我們調(diào)用Derived結(jié)構(gòu)體的Method1方法時,執(zhí)行的是我們在Derived結(jié)構(gòu)體中重新定義的方法,而不是Base結(jié)構(gòu)體的原始方法。

注意事項(xiàng)

  • 雖然結(jié)構(gòu)體嵌套實(shí)現(xiàn)了類似繼承的功能,但它與傳統(tǒng)的繼承機(jī)制還是有一些區(qū)別。例如,在Go語言中,沒有像其他語言中那樣的類層次結(jié)構(gòu)和多態(tài)性的嚴(yán)格語法定義。
  • 這種結(jié)構(gòu)體嵌套的方式在實(shí)際應(yīng)用中需要謹(jǐn)慎使用,要確保代碼的可讀性和可維護(hù)性。如果嵌套過于復(fù)雜,可能會導(dǎo)致代碼難以理解和維護(hù)。

多態(tài)

定義:多態(tài)是指不同類型的對象對同一方法調(diào)用可以表現(xiàn)出不同的行為。

實(shí)現(xiàn)方式:通過接口實(shí)現(xiàn)多態(tài),首先定義一個接口,接口中規(guī)定了一些方法,但沒有具體的實(shí)現(xiàn)。例如,定義一個Shape接口,要求實(shí)現(xiàn)Area方法:

type Shape interface {Area() float64
}

然后讓不同的結(jié)構(gòu)體實(shí)現(xiàn)這個接口。例如,RectangleSquare結(jié)構(gòu)體都可以實(shí)現(xiàn)Shape接口:

func (r Rectangle) Area() float64 {return r.length * r.width
}
func (s Square) Area() float64 {return s.sideLength * s.sideLength
}

當(dāng)使用接口類型的變量時,根據(jù)實(shí)際賦值的結(jié)構(gòu)體不同,調(diào)用Area方法會表現(xiàn)出不同的行為。例如:

var s Shape
r := Rectangle{length: 5, width: 3}
s = r
fmt.Println(s.Area()) // 輸出15
s1 := Square{sideLength: 4}
s = s1
fmt.Println(s.Area()) // 輸出16

通過接口實(shí)現(xiàn)了多態(tài),使得程序可以根據(jù)不同的對象類型靈活地執(zhí)行相應(yīng)的操作。

http://www.risenshineclean.com/news/33340.html

相關(guān)文章:

  • 蘇州吳中區(qū)做網(wǎng)站新東方教育培訓(xùn)機(jī)構(gòu)官網(wǎng)
  • wordpress恢復(fù)分類目錄seo營銷論文
  • 自動化東莞網(wǎng)站建設(shè)北京疫情最新消息
  • 網(wǎng)站開發(fā)視頻壓縮上傳seo資源
  • 旅游網(wǎng)站在提高用戶體驗(yàn)方面應(yīng)做哪些工作長春網(wǎng)站建設(shè)制作
  • 做吃的教程網(wǎng)站品牌整合營銷方案
  • 典型網(wǎng)站開發(fā)的一般流程推廣app是什么工作
  • 好看網(wǎng)站手機(jī)版批量查詢權(quán)重
  • 網(wǎng)站建設(shè)php帶數(shù)據(jù)庫模板網(wǎng)絡(luò)安全
  • 如何做網(wǎng)站鏡像百度鏈接提交入口
  • 手機(jī)網(wǎng)站有哪些類型成都網(wǎng)絡(luò)推廣
  • 網(wǎng)站建設(shè) 開發(fā)網(wǎng)站代碼百度網(wǎng)盤官網(wǎng)
  • 怎么用家里的電腦做網(wǎng)站服務(wù)器上海seo公司排名
  • 學(xué)校網(wǎng)站建設(shè)的優(yōu)勢和不足成人用品推廣網(wǎng)頁
  • 陽春網(wǎng)站制作寧波網(wǎng)站建設(shè)推廣平臺
  • 個人網(wǎng)站 備案 廣告seo搜索引擎優(yōu)化價格
  • 72搭建網(wǎng)站網(wǎng)頁代引流推廣公司
  • 想開個網(wǎng)站賣衣服的怎么做常州seo收費(fèi)
  • 有交做拼多多網(wǎng)站的嗎產(chǎn)品推廣平臺有哪些
  • 自己做網(wǎng)站賣什么海南樂秀同城群軟件下載
  • 做網(wǎng)站公司南京關(guān)鍵詞免費(fèi)網(wǎng)站
  • c 做網(wǎng)站設(shè)計(jì)關(guān)鍵詞排名提高方法
  • pageadmin如何做網(wǎng)站數(shù)據(jù)分析培訓(xùn)班
  • 代還信用卡網(wǎng)站建設(shè)國內(nèi)最新十大新聞
  • .net mvc做網(wǎng)站一鍵優(yōu)化清理
  • 單縣網(wǎng)站定制網(wǎng)絡(luò)營銷策劃的主要特點(diǎn)
  • 國外網(wǎng)站 服務(wù)器青島seo排名公司
  • 網(wǎng)頁即時聊天seo推廣怎么樣
  • 用動物做網(wǎng)站名稱可以投放廣告的網(wǎng)站
  • 沒有備案的網(wǎng)站可以做淘寶客seo網(wǎng)絡(luò)推廣培訓(xùn)班