AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當前位置:首頁 > 科技  > 軟件

Go語言的常用基礎

來源: 責編: 時間:2024-01-02 09:30:53 228觀看
導讀一、核心特性Go語言有一些讓人影響深刻的核心特性核心特性,比如:以消息傳遞模式的并發、獨特的_符號、defer 、函數和方法、值傳遞等等,可以查看這篇文章《Go語言-讓我印象深刻的13個特性》。首先要記住一些核心特性的用

一、核心特性

Go語言有一些讓人影響深刻的核心特性核心特性,比如:以消息傳遞模式的并發、獨特的_符號、defer 、函數和方法、值傳遞等等,可以查看這篇文章《Go語言-讓我印象深刻的13個特性》。首先要記住一些核心特性的用法。nGC28資訊網——每日最新資訊28at.com

nGC28資訊網——每日最新資訊28at.com

1.Goroutine

  • 協程:獨立的棧空間,共享堆空間,比線程更輕量。
  • 線程:一個線程上可以跑多個協程。
  • Go語言獨有的協程,讓程序員非常方便的使用并發編程,從而保留更多的心智去思考業務和創新。筆者認為這一點是Go語言最大的特性。

Goroutine就是這種協程特性的實現。Goroutine 是通過通信來共享內存,而不是共享內存來通信。通過共享內存來控制并發,會使編程變得更復雜,容易引入更多的問題。nGC28資訊網——每日最新資訊28at.com

Goroutine是由Go的運行時調度和管理。Go程序會智能地將 Goroutine 中的任務合理地分配給每個CPU,它在語言層面已經內置了調度和上下文切換的機制,不需要程序員去操作各種方法實現調度。nGC28資訊網——每日最新資訊28at.com

在Go語言中,當需要讓某個任務并發執行時,只需要把這個任務包裝成一個函數,開啟一個Goroutine去執行就可以了。如下,只需要在調用函數時,在前面加上go關鍵字。nGC28資訊網——每日最新資訊28at.com

func hello_go() {  fmt.Println("hello go!!!")}func main() {    go hello_go()    fmt.Println("main done!!!")    time.Sleep(time.Second)}

2.接口

在Go語言中接口interface是一種類型。Go語言的接口比較松散,只要是實現了接口定義的方法,就是實現了這個接口,無需使用implement等關鍵字去聲明。nGC28資訊網——每日最新資訊28at.com

定義接口:nGC28資訊網——每日最新資訊28at.com

// 定義接口type Sayer interface {  say()}// 定義結構體type dog struct {}type cat struct {}// 定義方法func (d dog) say() {  fmt.Println("狗叫")}func (c cat) say() {  fmt.Println("貓叫")}

空接口可以存儲任意類型:nGC28資訊網——每日最新資訊28at.com

// 比如定義一個map類型的對象var obj = map[string]interface{}

使用類型斷言判斷空接口中的值:nGC28資訊網——每日最新資訊28at.com

// x:表示類型為interface{}的變量// T:表示斷言x可能是的類型。x.(T)
func main() {  var x interface{}  x = 123  //v, ok := x.(int)  v, ok := x.(string)  if ok {    fmt.Println(v)  } else {    fmt.Println("類型斷言失敗")  }}

接口特性:nGC28資訊網——每日最新資訊28at.com

  • 接口類型變量能夠存儲所有實現了該接口的實例。 如下,Sayer類型的變量能夠存儲dog和cat類型的變量。
// 定義接口type Sayer interface {  say()}// 定義結構體type dog struct {}type cat struct {}// 定義方法func (d dog) say() {  fmt.Println("狗叫")}func (c cat) say() {  fmt.Println("貓叫")}func main(t *testing.T) {  var x Sayer // 聲明一個接口類型的變量  c := cat{}  // 實例化cat  d := dog{}  // 實例化dog  x = c       // cat賦值給接口類型  x.say()     // 打印:貓叫  x = d       // dog賦值給接口類型  x.say()     // 打印:狗叫}
  • 一個類型可以同時實現多個接口,接口間彼此獨立。
// 定義接口type Sayer interface {  say()}type Mover interface {  move()}// 定義結構體type dog struct {}// 定義方法func (d dog) say() {  fmt.Println("狗叫")}func (d dog) move() {  fmt.Println("狗移動")}func main(t *testing.T) {  var x Sayer  var y Mover  var d = dog{}  x = d  y = d  x.say()  y.move()}
  • 使用值接收者實現接口 和 使用指針接收者實現接口 有什么區別?值接受者實現時 可以用 指針類型賦值過去,但 指針接受者實現時 無法用 值類型賦值過去。
// 定義接口type Mover interface {  move()}type Sayer interface {  say()}// 定義結構體type dog struct {}// 定義方法func (d *dog) say() {  fmt.Println("狗叫")}func (d dog) move() {  fmt.Println("狗移動")}func TestProgram(t *testing.T) {  var x Sayer  var y Mover  //var d = dog{}  var d = &dog{}  x = d        // x不可以接收 dog類型,因為golang 不會 將值類型 轉換 為指針類型  y = d     // y可以接受  *dog類型,因為golang 會 將指針類型 轉換 為值類型  x.say()  y.move()}

3.下劃線

_是特殊標識符,用來忽略結果。nGC28資訊網——每日最新資訊28at.com

buf := make([]byte, 1024)f, _ := os.Open("/Users/***/Desktop/text.txt")

4.Go語言中的指針

  • &:用于獲取變量的地址,其實就是所謂的指針類型**(地址類型)
  • :用于獲取指針所指向的值*

nGC28資訊網——每日最新資訊28at.com

func main() {  a := 10  fmt.Printf("type of a: %T/n", a)  b := &a // 取變量a的地址,將指針保存到b中  fmt.Printf("type of b: %T/n", b)  c := *b // 取出 指針b 所指向的值  fmt.Printf("type of c: %T/n", c)  fmt.Printf("value of c: %v/n", c)}

5.new和make的區別

  • 二者都是用來做內存分配的。
  • make只用于slice、map、channel的初始化,返回的還是這三個引用類型本身。這里的引用有別于指針,他是對 slice、map、channel 值的間接訪問,并不是一個指向 slice、map、channel 的指針。
  • new用于類型的內存分配,并且內存對應的值為類型零值,返回的是指向類型的指針。指針是一個變量,存儲了值的內存地址。

6.defer延遲調用

關鍵字 defer 用于注冊延遲調用。這些調用直到 return 前才被執。可以用來做資源清理,常用來關閉資源。defer 是先進后出。nGC28資訊網——每日最新資訊28at.com

func main() {  arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}  for _, v := range arr {    defer fmt.Println("循環:", v)  }  fmt.Println("主流程跑完")  time.Sleep(time.Second * 3)  // 等待3秒后,執行defer,輸出時先輸出10,最后輸出1,因為是先進后出}

二、常用類型和內置函數

1.常用類型

bool                                // 布爾int, int8, int16, int32, int64      // 整數uint, uint8, uint16, uint32, uint64 // 0 和正整數float32, float64                    //浮點數string                              // 字符串complex64, complex128               // 數學里的復數array     // 固定長度的數組struct    // 結構體string    // 字符串slice     // 序列數組map       // 映射chan      // 管道interface // 接口 或 任意類型func      // 函數

2.常用內置函數

append          // 追加元素到數組copy            // 用于復制和連接slice,返回復制的數目len             // 求長度,比如string、array、slice、map、channelcap             // capacity是容量的意思,用于返回某個類型的最大容量(只能用于切片和 map)delete          // 從map中刪除key對應的valuepanic           // 拋出異常(panic和recover:用來做錯誤處理)recover         // 接受異常make            // 分配內存,返回Type本身(只能應用于slice, map, channel)new             // 分配內存,主要用來分配值類型,比如int、struct。返回指向Type的指針close           // 關閉channel

三、變量、常量

// 申明變量var name string// 申明常量const pi = 3.1415const e = 2.7182// 或const (        pi = 3.1415        e = 2.7182    )// 申明并且初始化n := 10

四、數據結構

1.數組

數組的長度固定:nGC28資訊網——每日最新資訊28at.com

var arr1 = [5]int{1, 2, 3, 4, 5}// 或arr2 := [...]struct {  name string  age  int8}{  {"yangling", 1},  {"baily", 2},}

2.切片

切片的長度不固定:nGC28資訊網——每日最新資訊28at.com

// 1.聲明切片var s1 []ints2 := []int{}var s3 = make([]int, 0)// 向切片中添加元素s1 = append(s1, 2, 3, 4)// 從切片中按照索引獲取切片s1[low:high]// 循環for index, element := range s1 {  fmt.Println("索引:", index, ",元素:", element)}

3.Map

scoreMap := make(map[string]int)scoreMap["張三"] = 90scoreMap["李四"] = 100userInfo := map[string]string{  "username": "baily",  "password": "111111",}// 如果key存在ok 為true,v為對應的值;// 如果key不存在ok 為false,v為值類型的零值v, ok := scoreMap["李四"]if ok {  fmt.Println(v)} else {  fmt.Println("查無此人")}// 循環for k, v := range scoreMap {  fmt.Println(k, v)}//將王五從map中刪除delete(scoreMap, "王五")

4.結構體

不同的使用方式,可能返回指針,也可能返回值。nGC28資訊網——每日最新資訊28at.com

// 定義結構體type Student struct {  name string  age  int}func main() {  // 使用結構體  // 方式1,返回的是值  var stu1 Student  stu1.name = "baily"  stu1.age = 1  fmt.Println("baily1:", stu1)  // 方式2,返回的是值  var stu2 = Student{    name: "baily",    age:  1,  }  fmt.Println("baily2:", stu2)  // 方式3,返回的是指針  stu3 := &Student{    name: "baily",    age:  1,  }  fmt.Println("baily3指針:", stu3)  fmt.Println("baily3值:", *stu3)  // 方式4,返回的是指針  var stu4 = new(Student)  stu4.name = "baily"  stu4.age = 1  fmt.Println("baily4指針:", stu4)  fmt.Println("baily4值:", *stu4)}

五、流程控制

流程控制包括:if、switch、for、range、select、goto、continue、break。主要記下select,其他的跟別的語言類似。主要用于等待資源、阻塞等待等等。nGC28資訊網——每日最新資訊28at.com

select 語句類似于 switch 語句,但是select會隨機執行一個可運行的case。如果沒有case可運行,它將阻塞,直到有case可運行。nGC28資訊網——每日最新資訊28at.com

func main() {  var c1 = make(chan int)  go func() {    time.Sleep(time.Second * 10)    c1 <- 1  }()  // 此處會一直等到10S到期,通道里有值才會繼續往下走。  // 如果增加了 time.After(time.Second * 3) ,則最多3秒則結束  // 如果這2個case都不行,會走default,也可以不設置default  select {  case i, ok := <-c1:    if ok {      fmt.Println("取值", i)    }  case <-time.After(time.Second * 3):    fmt.Println("request time out")  default:    fmt.Println("無數據")  }}

六、函數和閉包

1.函數

// 正常函數func test(x int, y int, s string) (int, string) {    n := x + y              return n, fmt.Sprintf(s, n)}// 匿名函數func main() {    getSqrt := func(a float64) float64 {        return math.Sqrt(a)    }    fmt.Println(getSqrt(4))}

2.閉包

在Go語言中,閉包是一種函數值,它引用了其函數體外部的變量。閉包允許函數訪問并處理其外部范圍內的變量,即使函數已經返回了,這些外部變量也會被保留在閉包內。nGC28資訊網——每日最新資訊28at.com

所以說,一個閉包由兩部分組成:函數體 和 與其相關的引用外部變量的環境。nGC28資訊網——每日最新資訊28at.com

當一個函數被定義在另一個函數內部時,并且引用了外部函數的變量,就會創建一個閉包。這個閉包函數可以隨時訪問和修改外部函數中的變量,即使外部函數已經執行完畢。nGC28資訊網——每日最新資訊28at.com

func main() {  // 外部函數定義并返回內部函數  add := adder()    // 通過閉包調用內部函數,increment是閉包函數  fmt.Println(add(1)) // 輸出:1  fmt.Println(add(2)) // 輸出:3  fmt.Println(add(3)) // 輸出:6}// 外部函數,返回一個閉包函數func adder() func(int) int {  sum := 0 // 外部函數中的變量  // 閉包函數  return func(x int) int {    sum += x // 閉包函數使用了外部函數中的變量    return sum  }}

七、異常

1.內置接口error

type error interface { //只要實現了Error()函數,返回值為string的都實現了err接口   Error()    string}

2.異常處理

使用 panic 拋出錯誤,然后在defer中通過recover捕獲異常。nGC28資訊網——每日最新資訊28at.com

func main() {    testPanic()}func testPanic() {  defer func() {    if err := recover(); err != nil {      fmt.Println(err.(string))    }  }()  panic("拋出異常")}

3.返回異常

// 隱式地返回2個值func getCircleArea(radius float32) (area float32, err error) {  if radius < 0 {    // 構建個異常對象    err = errors.New("半徑不能為負")    return  }  area = 3.14 * radius * radius  return}func main() {  area, err := getCircleArea(-5)  if err != nil {    fmt.Println(err)  } else {    fmt.Println(area)  }}

八、面向對象和方法

11.面向對象

可以使用匿名字段:nGC28資訊網——每日最新資訊28at.com

type Person struct {  name string  age  int}type Student struct {  Person  id   int  addr string}func main() {    s1 := Student{      Person{"baily", 20},      1,      "南京市雨花臺區南京南站",    }    fmt.Println(s1)}

如果對象內部嵌套的對象有同名字段的情況,只取對象自己的字段:nGC28資訊網——每日最新資訊28at.com

type Person struct {  name string  age  int}type Student struct {  Person  id   int  addr string  name string}func main() {  var s Student  s.name = "baily"  s.Person.name = "baily-parent"  fmt.Println(s) // 打印出 baily   }

2.方法

一個方法就是一個包含了接受者的函數,接受者可以是 類型或者結構體 的值或者指針。nGC28資訊網——每日最新資訊28at.com

type Test struct{}// 多參數、多返回值func (t Test) method1(x, y int) (z int, err error) {  return}// 多參數、多返回值func (t *Test) method2(x, y int) (z int, err error) {  return}

3.指針接受者 和 值接受者的區別

當方法作用于值接收者時,Go語言會在代碼運行時將接收者的值復制一份。在值接收者的方法中可以獲取接收者的成員值,但修改操作只是針對復制出來的副本,無法修改接收者本身。nGC28資訊網——每日最新資訊28at.com

而指針接受者,在修改成員時,會修改接受者本身。nGC28資訊網——每日最新資訊28at.com

// SetAge 設置p的年齡// 使用指針接收者func (p *Person) SetAge(newAge int) {  p.age = newAge}// SetAge2 設置p的年齡// 使用值接收者func (p Person) SetAge2(newAge int) {  p.age = newAge}func main() {  p := new(Person)  p.age = 11  p.SetAge(22)   // 對象p的age會被改變  fmt.Println(p.age)  p.SetAge2(33)  // 對象p的age不會被改變  fmt.Println(p.age)}

什么時候應該使用指針接受者?nGC28資訊網——每日最新資訊28at.com

  • 需要修改接收者中的值
  • 接收者是拷貝代價比較大的大對象
  • 保證一致性,如果有某個方法使用了指針接收者,那么其他的方法也應該使用指針接收者。

九、網絡編程

TCP編程:nGC28資訊網——每日最新資訊28at.com

// 處理函數func process(conn net.Conn) {  defer conn.Close() // 關閉連接  for {    reader := bufio.NewReader(conn)    var buf [128]byte    n, err := reader.Read(buf[:]) // 讀取數據    if err != nil {      fmt.Println("讀取客戶端數據失敗:", err)      break    }    recvStr := string(buf[:n])    fmt.Println("收到client端發來的數據:", recvStr)    conn.Write([]byte("回復客戶端:" + recvStr)) // 發送數據  }}func main() {  listen, err := net.Listen("tcp", "127.0.0.1:9587")  if err != nil {    fmt.Println("啟動監聽異常:", err)    return  }  for {    conn, err := listen.Accept() // 建立連接    if err != nil {      fmt.Println("沒有連接:", err)      continue    }    go process(conn) // 啟動一個goroutine處理連接  }}

十、并發編程

1.使用sync.WaitGroup

var wg sync.WaitGroupfunc hello_wg(i int) {  defer wg.Done() // goroutine結束就登記-1  fmt.Println("hello_wg!", i)}func main() {  for i := 0; i < 10; i++ {    wg.Add(1) // 啟動一個goroutine就登記+1    go hello_wg(i)    time.Sleep(time.Second)  }  wg.Wait() // 等待所有登記的goroutine都結束}

2.使用channel解決并發

Go語言的并發模型是CSP(Communicating Sequential Processes),通過通信共享內存,而不是通過共享內存而實現通信。nGC28資訊網——每日最新資訊28at.com

nGC28資訊網——每日最新資訊28at.com

func recv(c chan int) {  ret := <-c  fmt.Println("接收成功", ret)}func main() {  c := make(chan int)  go recv(c) // 啟用goroutine從通道接收值  c <- 10  fmt.Println("發送成功")   }

3.select

func main() {  var c1 = make(chan int)  go func() {    time.Sleep(time.Second * 10)    c1 <- 1  }()  // 此處會一直等到10S到期,通道里有值才會繼續往下走。  // 如果增加了 time.After(time.Second * 3) ,則最多3秒則結束  // 如果這2個case都不行,會走default,也可以不設置default  select {  case i, ok := <-c1:    if ok {      fmt.Println("取值", i)    }  case <-time.After(time.Second * 3):    fmt.Println("request time out")  default:    fmt.Println("無數據")  }}

4.互斥鎖

多個go協程操作同一個資源時,會發生并發問題,需要加鎖解決。有互斥鎖,還有讀寫鎖。nGC28資訊網——每日最新資訊28at.com

func add() {  for i := 0; i < 5000; i++ {    // 如果不加鎖,此處會有并發問題    lock.Lock() // 加鎖    x = x + 1    lock.Unlock() // 解鎖  }  wg.Done()}func main() {  wg.Add(2)  go add()  go add()  wg.Wait()  fmt.Println(x)   }

十一、單元測試

文件以_test.go結尾,方法以Test開頭,方法入參t *testing.T。nGC28資訊網——每日最新資訊28at.com

func TestProgram(t *testing.T) {  split := strings.Split("a,b,c", ",")  defer func() {    if err := recover(); err != nil {      fmt.Println("異常:", err)    }  }()  findElement(split, "a")}// 查找元素func findElement(split []string, target string) {  flag := false  for _, e := range split {    if e == target {      flag = true      break    }  }  if flag {    fmt.Println("已經找到")  } else {    panic("沒找到")  }}

十二、常用命令

  • go env:用于打印Go語言的環境信息。
  • go build:用于編譯Go程序。例如,go build filename.go 會將 filename.go 編譯成可執行文件。
  • go run:用于直接運行Go程序。例如,go run filename.go 會編譯并運行 filename.go 文件中的程序。
  • go test:用于運行測試文件或者測試包。例如,go test 會運行當前目錄下所有的測試文件。
  • go get:用于下載并安裝包。例如,go get github.com/example/package 會下載 github.com/example/package 包并將其安裝在 $GOPATH/src 下。
  • go mod:用于管理依賴和模塊。例如,go mod init 用于初始化一個新的模塊,并生成 go.mod 文件。
  • go vet:用于靜態檢查Go代碼中的錯誤。例如,go vet filename.go 會檢查 filename.go 文件中的錯誤。
  • go install 命令用于編譯并安裝Go程序,它會編譯指定的包或源文件,并將生成的可執行文件安裝到 $GOPATH/bin 目錄下。

本文鏈接:http://www.tebozhan.com/showinfo-26-55136-0.htmlGo語言的常用基礎

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Typedef在C語言和C++中有什么區別?

下一篇: 通過Uri加載raw目錄下的文件

標簽:
  • 熱門焦點
  • K60 Pro官方停產 第三方瞬間漲價

    雖然沒有官方宣布,但Redmi的一些高管也已經透露了,Redmi K60 Pro已經停產且不會補貨,這一切都是為了即將到來的K60 Ultra鋪路,屬于廠家的正常操作。但有意思的是該機在停產之后
  • 7月安卓手機性能榜:紅魔8S Pro再奪榜首

    7月份的手機市場風平浪靜,除了紅魔和努比亞帶來了兩款搭載驍龍8Gen2領先版處理器的新機之外,別的也想不到有什么新品了,這也正常,通常6月7月都是手機廠商修整的時間,進入8月份之
  • Rust中的高吞吐量流處理

    作者 | Noz編譯 | 王瑞平本篇文章主要介紹了Rust中流處理的概念、方法和優化。作者不僅介紹了流處理的基本概念以及Rust中常用的流處理庫,還使用這些庫實現了一個流處理程序
  • 企業采用CRM系統的11個好處

    客戶關系管理(CRM)軟件可以為企業提供很多的好處,從客戶保留到提高生產力。  CRM軟件用于企業收集客戶互動,以改善客戶體驗和滿意度。  CRM軟件市場規模如今超過580
  • 微軟邀請 Microsoft 365 商業用戶,測試視頻編輯器 Clipchamp

    8 月 1 日消息,微軟近日宣布即將面向 Microsoft 365 商業用戶,開放 Clipchamp 應用,邀請用戶通過該應用來編輯視頻。微軟于 2021 年收購 Clipchamp,隨后開始逐步整合到 Microsof
  • 電視息屏休眠仍有網絡上傳 愛奇藝被質疑“薅消費者羊毛”

    記者丨寧曉敏 見習生丨汗青出品丨鰲頭財經(theSankei) 前不久,愛奇藝發布了一份亮眼的一季報,不僅營收和會員營收創造歷史最佳表現,其運營利潤也連續6個月實現增長。自去年年初
  • 三星Galaxy Z Fold5官方渲染圖曝光:13.4mm折疊厚度依舊感人

    據官方此前宣布,三星將于7月26日在韓國首爾舉辦Unpacked活動,屆時將帶來帶來包括Galaxy Buds 3、Galaxy Watch 6、Galaxy Tab S9、Galaxy Z Flip 5、
  • 2299元起!iQOO Pad開啟預售:性能最強天璣平板

    5月23日,iQOO如期舉行了新品發布會,除了首發安卓最強旗艦處理器的iQOO Neo8系列新機外,還在發布會上推出了旗下首款平板電腦——iQOO Pad,其搭載了天璣
  • 滴滴違法違規被罰80.26億 共存在16項違法事實

    滴滴違法違規被罰80.26億 存在16項違法事實開始于2121年7月,歷經一年時間,網絡安全審查辦公室對“滴滴出行”網絡安全審查終于有了一個暫時的結束。據“網信
Top