【基礎】go基礎學習筆記

基礎及關鍵字
  • if for switch都支持使用隱形聲明(:=)來快速聲明一個變量,無需在上面一行額外聲明,這可以增加代碼簡潔性,但不太符合其他常規語言的寫法,需要習慣一下

  • if for switch都不需要使用()包裹表達式,只使用空格隔開就行

  • 大寫的函數或變量才算是對外聲明(用開頭大寫來代替其他語言中的public private\export的概念)

  • 基礎類型轉換是顯式的,使用類型本身加(),值寫在括號中,即可完成類型轉換

  • 導包和聲明變量都支持使用()批量聲明,這可以增加代碼簡潔性,也可以像其他語言一樣一條條聲明,也沒問題

  • switch的case匹配到后就直接停止,不會像其他語言一樣一路向后繼續匹配,除非以 fallthrough 語句結束

  • for關鍵字支持省略聲明、條件、表達式三個部分,這直接代替別的語言中的while了

  • 聲明變量、方法參數、方法返回值時當多個參數類型重復時都支持省略類型,這可以有效減少重復代碼,但也容易出bug,寫法: x, y, z int

  • go中各種表達式都使用分號;隔開

  • 方法return支持多值return,只要方法的return類型定義時多定義幾個就好了,小括號括起來,用逗號隔開

  • 盡量避免使用隱式return(方法需要返回值時,直接一個return將函數中的所有變量都返回掉),因為隱式return容易出現問題(太依賴編譯器,函數后續不好修改)

  • go中的返回值也支持聲明類型的同時給其命名,這就更能說明不要使用隱式return了,容易出現問題

  • 循環中使用break跳出

  • defer關鍵字是defer語句所在的函數運行完成后再調用被defer修飾的代碼,defer調用的函數會被壓棧,會遵從后進先出的順序依次調用

  • 以下函數很違反直覺:

package mainimport "fmt"func main() {fmt.Println("counting")defer fmt.Println("done")i := 0;for ; i < 10; i++ {defer fmt.Println(i)}
}

結果:

counting
9
8
7
6
5
4
3
2
1
0
done
指針
  • 指針直接指向內存地址,操作指針等于操作該值本身。
  • 使用&對某個變量產生一個指針:&i,使用*修飾T(類型)來聲明一個指針:p *int,使用*p的方式來解引用指針(使用指針)。
  • &表示取地址,A變量被取地址后賦值給新的變量B,這個變量B就成為了變量A的指針,直接打印變量B時只會打印出內存地址
  • *表示解引用,變量B目前是指針,使用*對變量B進行解引用,即*B就可以打印原來的變量A的值,解引用后的*B和原來的A的值是完全一樣的,即內存上存儲使用的是同一份。
  • 列表指針寫法: *List[T]指針的指針寫法: **List[T],指針的指針是要修改的變量的指針的指針,不常用但是在一些特殊場景很有用,通常用在替換要修改的變量的指針本身時使用,口述比較繞,但是看一個關于鏈表的代碼例子就明白了:
// 在 main 函數中,我們的鏈表頭是一個指針
var listHead *List[T] = nil // 一開始是空鏈表// 我們希望 Push 函數能修改 listHead 這個指針,讓它指向一個新的節點。
func (l **List[T]) Push(v T) {// 如果我們只接收 *List[T],那么 l 只是 listHead 的一個副本。// 我們需要修改 listHead 本身,所以必須接收它的地址,即 **List[T]。// *l 的意思就是:“通過這把鑰匙,拿到 main 函數里的那張原始藏寶圖(listHead 指針)”// 然后我們修改這張原始藏寶圖,讓它指向一個新的寶藏(新節點)。*l = &List[T]{next: *l, val: v}
}
  • 黃金法則:想修改什么,就向函數傳遞它的指針,不論是變量還是指針本身
  • 直接給指針本身賦值時,必須也要賦值指針,不能賦值值本身
結構體
  • go中聲明結構體(類似于類)使用type 結構體名稱 struct加大括號:
type Vertex struct {X intY int
}
  • 實例化結構體:
v := Vertex{1, 2}//允許如下方式實例化結構
v := Vertex{X: 1} //對X賦值使用冒號而不是等號,這里Y就是0,println(v)打印結果是 {1 0}
  • 配合結構體使用:
p := &v
等價于
var p *Vertex = &v

go允許隱式解引用,即直接省略和星號和大括號對結構體引用進行使用:

p.X = 1e9
等價于
(*p).X = 1e9
數組和切片
  • 數組聲明方式:var a [2]string,與其他語言不同的是數量和中括號放在了類型前邊
  • 初始化數組的方式:var a [2]string,帶初始值的方式: a := [2]string{"hello", "world"} 或者 var c [2]string = [2]string{"hello", "world"}
  • 數組和切片的區別是數組聲明時必須指定長度,而切片則由編譯器推導。數組是實際存儲值的,而切片不存儲值(只是相當于數組中某段元素的引用),切片更常用
  • 切片遵從要頭不要尾,a[1:4]表示取數組的1,2,3下標的元素,不包含4
  • 切片類似于數組的引用,即它描述了數組中的某段元素,修改切片等于直接修改數組本身
  • 構建數組時中括號[]里不寫數字,就相當于構建了一個數組+切片,注意,這樣的話長度其實仍然固定,如果直接給超過聲明長度的下標賦值或取值就會報越界錯誤
  • 切片可以忽略上界和下界:
//切片下界的默認值為 0,上界則是該切片的長度。//對于數組 var a [10]int 來說,以下切片表達式和它是等價的:a[0:10]
a[:10]
a[0:]
a[:]
  • make(內置函數)用來創建動態數組,比較常用:
//第三個參數cap可以省略,也可以手動指定
b := make([]int, 0, 5) // len(b)=0, cap(b)=5
  • 數組的len可以理解為數組長度,cap可以理解為容量。容量總是大于等于長度的。
  • 切片的類型可以是任意類型包括結構體或切片等,例如[][]string[]struct
  • append(內置函數)用來為切片追加值:
v := []int{0,1} //聲明切片
v = append(v, 2, 3, 4) //追加多個值
fmt.Println(v) //結果:[0 1 2 3 4] 
  • 使用range關鍵字遍歷切片或數組
  • 在go中利用切片結合uint8的對應灰度值來渲染一張圖片,關鍵點就是對切片本身的使用:
package mainimport (
"golang.org/x/tour/pic"
)func Pic(dx, dy int) [][]uint8 {outerSlice := make([][]uint8 ,dy)for y := range outerSlice {innerSlice := make([]uint8, dx)for x := range innerSlice {v := x*x+y*y //改變這里可以改變結果圖片的效果,例如:(x+y)/2、x*y、x^y、x*log(y) 、x%(y+1)、x*x、y*y 、x * math.Log(float64(y))等innerSlice[x] = uint8(v)}outerSlice[y] = innerSlice}return outerSlice
}func main() {pic.Show(Pic)
}
map(映射)
  • 創建map可以使用make函數,聲明map類型時的格式如:map[string]string,第一個中括號中的為鍵類型可以是任意類型,通常是string,后面緊跟著的是值類型,可以是任意類型
  • map創建時后面的大括號類似于kotlin中的mapOf,不過把to換成了冒號
  • 通過雙賦值表達式檢測鍵是否存在:
v, exsit := m["答案"]
fmt.Println("值:", v, "是否存在?", exsit)
函數(方法)
  • 函數可以作為參數傳遞,參數類型為func,函數可以賦值給一個變量,該變量即成為函數本身,跟js中的函數特點有點像,函數類型也可以作為另一個函數的返回值
  • 函數的閉包通常可以用于統計和累計,這很有用,可以省去一些不必要的外部全局變量
  • 一段不正確的斐波那契數列計算代碼,這段代碼跳過了開頭的0和1的輸出:
package mainimport "fmt"// fibonacci 是返回一個「返回一個 int 的函數」的函數
func fibonacci() func() int {r := []int{0,1}return func () int {sum := r[len(r)-1] + r[len(r)-2]r = append(r,sum)//fmt.Println(r)//fmt.Println( r[len(r)-1:len(r)][0] )return sum}
}func main() {f := fibonacci()for i := 0; i < 10; i++ {fmt.Print(f()," ")}
}//會打印 :1 2 3 5 8 13 21 34 55 89

修正思路為每次調用時,第一個值正是要返回的結果,而后只使用最新的兩個數字來保持狀態值最新,下面是修正后的函數:

func fibonacci() func() int {a,b := 0,1return func () int {ret := aa,b = b,a+breturn ret}
}//打印:0 1 1 2 3 5 8 13 21 34
  • 為結構體(或基礎類型)定義方法的方式就是使用括號包含具體的帶名稱的類型,類似于kotlin的擴展方法,但是不能定義在結構體內,也必須得聲明一個名稱來引用而不是this
//定義
type Vertex struct {X, Y float64
}func (v Vertex) Abs() float64 {return math.Sqrt(v.X*v.X + v.Y*v.Y)
}//使用
v := Vertex{3, 4}
fmt.Println(v.Abs())

為類型定義方法的方式是使用type轉一下類型:

//定義
type MyFloat float64func (f MyFloat) Abs() float64 {if f < 0 {return float64(-f)}return float64(f)
}//使用
f := MyFloat(-math.Sqrt2)
fmt.Println(f.Abs())
  • 不能跨包定義方法
  • 為指針類型接收者定義方法通常更常用,因為有時需要通過該方法來修改結構體的數據并使其在后續生效:
package mainimport ("fmt"
)type Vertex struct {A,B int
}//沒有對v(指針型類型接收者)進行修改的能力
func (v Vertex) Sum() int {return v.A+v.B
}//有對v進行修改的能力
func (v *Vertex) Scale(l int) {v.A = v.A * lv.B = v.B * l
}//使用
func main() {v := Vertex{3, 4}v.Scale(10)fmt.Println(v.Sum())
}//打印70
  • 如果不確定,或者想修改接收者,用指針接收者通常是更安全、更通用的選擇,定義為指針接收者通常對性能也有很大的幫助,可以避免復制開銷
  • go的語法糖:1.定義為指針型接收者的方法,在調用時也直接允許值類型的進行調用 2.定義為值型接受者的方法,在調用時也允許指針類型進行調用
  • 當一個方法實現了接口或者作為結構體的方法,有入參,有多個響應值,且響應值中有方法類型時,這個方法看起來會很奇怪,有多達4個或更多的括號,但是卻有效合法,如下復雜示例:
package mainimport "fmt"type Vertex struct{X,Y int
}//Vertex類型的專屬異常
type VertexError struct {V Vertex
}//Vertex類型的專屬異常處理
func (e *VertexError) Error() string {return fmt.Sprintf("vertex error on value: %+v", e.V)
}//復雜函數
func (v *Vertex) Sum(scale func(int) int) (int,(func(int) int), error){if v.X == -1 {return 0, nil, &VertexError{*v}}return scale(v.X) + scale(v.Y),scale,nil
}func Scale(s int) int {return s * s
}func main() {v := Vertex{-1,2} //-1時會觸發異常s,f,err := v.Sum(Scale)if err != nil {fmt.Printf("error: %v",err)return}fmt.Printf("s: %v f: %v",s,f)
}

接口

  • go中的接口使用interface關鍵字,沒有顯示的類似于其他語言中的"implements"或冒號等定義,某個類型的方法只要包含目標接口的全部方法,就可以說該類型實現了目標接口,沒有代碼上顯式的引用和定義關系
  • 弊端是無法一眼看出某個類型到底實現了某個接口沒有,好處就是代碼靈活
  • 接口也是值,可以在方法參數、返回值、變量等進行傳遞
  • 空接口是一個特殊定義: interface {},可以保存任何類型的值內容,類似于kotlin中的Any?或java中的Object+null類型
  • 類型斷言,格式和寫法: i.(string),具體用法如下,可以檢查出該接口底層保存的值以及是否使用的是對應的類型:
   var i interface{} = "hello"s := i.(string)fmt.Println(s) //hellos, ok := i.(string)fmt.Println(s, ok) //hello truef, ok := i.(float64)fmt.Println(f, ok) //0 falsef = i.(float64) // panicfmt.Println(f) //panic: interface conversion: interface {} is string, not float64

用來檢查并獲取值確實不錯,看起來挺好用的

  • 類型選擇,格式和寫法: i.(type){ case ... }, 類型選擇的寫法如下,可以通過類似switch的方式檢查對應接口值是否是該類型:
package mainimport "fmt"func do(i interface{}) {switch v := i.(type) {case int:fmt.Println("是int類型")case string:fmt.Println("是string類型")default:fmt.Println("未知類型", v)}
}func main() {do(21) //是int類型do("hello") //是string類型do(true) //未知類型 true
}
  • 方法調用的返回值可以主動的響應error,通過判斷error是否為空:if err != nil來進行錯誤處理:
package mainimport ("errors""fmt"
)func Div(a, b int) (int, error) {if b == 0 {return 0, errors.New("b is 0!") //拋出一個錯誤}return a / b, nil
}func main() {div, err := Div(3, 0)if err != nil {fmt.Println(err) //b is 0!return //提前返回}fmt.Println(div)
}
  • error是一個內置接口,可以輕松使用方法對某個類型定義特定的錯誤處理,實現: Error() string方法即可
  • 錯誤處理完后應當立即返回,通常使用return或者log.Fatal
  • 實現接口可以做很多事情,一種常見的好處就是解耦且不用關注額外細節就能實現強大的功能,因為方法參數如果是接口類型的,那么傳入的實例只要能實現對應接口的所有方法,就可以正確作為參數,至于方法內部如何,應該根據方法實際情況來完成實現
  • 實現了圖片接口的結構體,可以借助pic庫完成圖片繪制,耦合性很低,表現力很高,示例:
package mainimport ("golang.org/x/tour/pic""image""image/color"
)// Image 是我們將要定義的自定義圖片類型。
// 它是一個空結構體,因為我們不需要存儲任何數據。
// 圖像的像素是動態計算出來的。
type Image struct{}// Bounds 方法返回圖像的尺寸。
// 我們定義一個 256x256 像素的圖像。
func (i Image) Bounds() image.Rectangle {return image.Rect(0, 0, 256, 256)
}// ColorModel 返回圖像的顏色模型。
// 我們使用標準的 RGBA 模型。
func (i Image) ColorModel() color.Model {return color.RGBAModel
}// At 方法是核心。它在給定的 (x, y) 坐標處返回一個顏色。
// 渲染程序會為圖像中的每一個像素調用一次此方法。
func (i Image) At(x, y int) color.Color {// 使用 x 和 y 坐標通過一個簡單的函數生成一個值。// 這里的 x^y 是按位異或(XOR)操作,能產生有趣的圖案。v := uint8(x ^ y)// 返回一個 RGBA 顏色。// R(紅)= v, G(綠)= v, B(藍)= 255, A(透明度)= 255(不透明)// 這會產生一個藍色的、帶有漸變紋理的圖像。return color.RGBA{v, v, 255, 255}
}func main() {// 創建我們自定義 Image 類型的一個實例。m := Image{}// pic.ShowImage 會接收任何實現了 image.Image 接口的類型,// 并將其渲染成圖片(在 Go Tour 中是 base64 編碼的 PNG)。pic.ShowImage(m)
}
類(泛)型參數
  • 類似于其他語言中的泛型
  • 聲明方式:func Index[T comparable](s []T, x T) int,這表示s的元素類型可以是滿足了 comparable接口的所有類型,x 的類型也是滿足了 comparable接口的所有類型

雜項

  • 遍歷鏈表:
//常見的需要取值的標準寫法:
for n := l; n != nil; n = n.next//將鏈表撥動到最后位置的寫法:
current := *l
for current.next != nil {current = current.next
}
  • 構建字符串使用strings.Builder,方法是WriteString,獲取結果是string()

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/92777.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/92777.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/92777.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

AI驅動的企業知識管理革新

Baklib&#xff1a;人工智能引領的知識管理平臺Baklib 是領先的 AI 驅動知識管理系統&#xff0c;專為企業打造智能化、模塊化的知識共享平臺。功能覆蓋在線幫助中心、內聯網、CMS 網站、客戶支持系統、視頻中心、活動教學平臺和客戶社區&#xff0c;全面提升組織在知識管理、員…

使用 FFmpeg 實現 RTP 音頻傳輸與播放

&#x1f50a; 使用 FFmpeg 實現 RTP 音頻傳輸與播放&#xff08;Ubuntu&#xff09; 在音視頻開發或遠程通信場景中&#xff0c;RTP&#xff08;Real-time Transport Protocol&#xff09; 是一種常用的實時音頻傳輸協議。本文將介紹如何使用 FFmpeg 在 Ubuntu 上實現從一臺主…

Android 導出聯系人為 vCard(.vcf)

有時需要將聯系人數據導出為可共享的標準格式&#xff1a;vCard&#xff08;.vcf&#xff09;格式&#xff0c;可被系統直接導入通訊錄一、導出聯系人為 vCard&#xff08;.vcf&#xff09;? 支持字段我們支持導出的字段包括&#xff1a;姓名個人電話家庭電話工作電話郵箱備注…

大模型-bacth之chunked prefills

一、chunked prefills 1.1 chunked prefills核心思想 ORCA雖然很優秀&#xff0c;但是依然存在兩個問題&#xff1a;GPU利用率不高&#xff0c;流水線依然可能導致氣泡問題。 我們來看sarathi-serve做的一個實驗。左右兩圖分別刻畫了在不同的batch size下&#xff0c;prefil…

multiprocessing模塊使用方法(一)

結合Python代碼示例說明multiprocessing模塊的使用方法、Linux啟動命令、服務部署及真實應用場景&#xff1a;一、multiprocessing基礎用法 Python的multiprocessing模塊通過創建子進程實現并行計算&#xff0c;核心步驟如下&#xff08;引用&#xff09;&#xff1a;創建進程對…

vector如何判斷應該擴容?

std::vector 的擴容機制是 C 容器性能優化的一個核心點。它的判斷標準、行為特征和實現細節如下所示&#xff1a;? 一、vector 的核心結構 std::vector 內部維護三個指針&#xff1a; begin -> 指向數據起始位置 end -> 指向當前已使用的元素末尾&#xff08;size…

ICMP考點

在網絡工程師、運維工程師、安全工程師等崗位的面試中&#xff0c;??ICMP&#xff08;Internet Control Message Protocol&#xff0c;互聯網控制報文協議&#xff09;?? 是高頻必考知識點。ICMP作為IP協議的“輔助協議”&#xff0c;雖然不直接傳輸用戶數據&#xff0c;但…

服務器帶寬具體是指什么意思?

企業在選擇服務器租用或托管服務時&#xff0c;需要根據自身的業務情況來選擇合適的服務器帶寬&#xff0c;以便于能夠讓其業務持續穩定的運行工作&#xff0c;做到及時響應用戶的訪問請求&#xff0c;但是很多用戶對于帶寬一詞沒有過多的概念&#xff0c;本文就來探討一下服務…

CANape之ASAP2 Studio介紹

提到ECU的測量標定工具&#xff0c;很多小伙伴第一個想到的就是CANape。但其實&#xff0c;除了強大的測量標定功能之外&#xff0c;CANape還有很多其他功能。例如&#xff0c;CANape中集成的小工具——ASAP2 Studio&#xff0c;其支持對A2L文件&#xff08;由ASAM組織所定義&a…

【debug日記】MONAI SwinUNETR 目標檢測項目調試總結(AI自動總結)

MONAI SwinUNETR 目標檢測項目調試總結 日期: 2025年7月25日 項目: 使用 MONAI&#xff0c;以預訓練的 SwinUNETR 為骨干網絡&#xff0c;微調 RetinaNet 進行3D肺結節檢測。 本文檔旨在記錄在項目配置、數據處理和模型訓練過程中遇到的一系列問題及其解決方案&#xff0c;作為…

AI同傳領域,字節跳動與科大訊飛激戰進行時

在AI同聲傳譯市場&#xff0c;行業巨頭科大訊飛長期占據主導地位&#xff0c;但新晉玩家字節跳動正以迅猛姿態發起挑戰。7月24日&#xff0c;字節旗下火山引擎正式發布豆包同聲傳譯模型 Seed LiveInterpret 2.0&#xff0c;主打“人類級延遲”和“0樣本聲音復刻”&#xff0c;試…

[C++]string::substr

string substr (size_t pos 0, size_t len npos) const;substr() 主要功能是復制&#xff08;截取更準確&#xff09;子字符串&#xff0c;要求從指定位置 pos 開始&#xff0c;并具有指定的長度 len 。如果沒有指定長度或者超出了源字符串的長度&#xff0c;則子字符串將延續…

KNN算法:從原理到實戰全解析

一 算法介紹 K近鄰&#xff08;K-Nearest Neighbors, KNN&#xff09;是一種基于實例的監督學習算法&#xff0c;適用于分類和回歸任務。其核心思想是通過計算待預測樣本與訓練集中樣本的距離&#xff0c;選取距離最近的K個鄰居&#xff0c;根據這些鄰居的標簽進行投票&#xf…

醫療器械:DFEMA和PFEMA

在醫療器械行業&#xff0c;DFMEA&#xff08;Design FMEA&#xff0c;設計失效模式及影響分析&#xff09;和 PFMEA&#xff08;Process FMEA&#xff0c;過程失效模式及影響分析&#xff09;是核心的風險管理工具&#xff0c;旨在通過系統性識別潛在風險、分析影響并采取預防…

Qt 與 SQLite 嵌入式數據庫開發

Qt 與 SQLite 的結合是開發輕量級、跨平臺嵌入式數據庫應用的理想選擇。SQLite 作為一種零配置、文件型數據庫&#xff0c;無需獨立的服務器進程&#xff0c;非常適合集成到 Qt 應用中。本文將深入探討 Qt 與 SQLite 的嵌入式數據庫開發&#xff0c;包括基礎操作、高級特性、性…

Oracle OMF 非OMF 文件 轉化 不需要重建 file#.incarnation#

不需要重建就要重啟&#xff0c; alter database datafile move 就可以在線 file#.incarnation# 是 incarnation 不是dbid Goal How to convert non OMF files to OMF files with ASM storage Datafiles are not deleted at dropping tablespace if files are non-OMF and …

大型微服務項目:聽書——11 Redisson分布式布隆過濾器+Redisson分布式鎖改造專輯詳情接口

11 Redisson分布式布隆過濾器Redisson分布式鎖改造專輯詳情接口 11.1 緩存穿透解決方案&布隆過濾器 緩存穿透解決方案&#xff1a; 布隆過濾器&#xff1a; 布隆過濾器的使用&#xff1a; 11.2 遠程調用查詢所有的專輯id集合 修改&#xff1a; /*** 查詢所有的專輯…

STM32與ADS1220實現多通道數據采集的完整分析和源程序

以下是基于STM32與ADS1220實現多通道數據采集的完整分析和源程序,結合硬件設計、通信協議及軟件優化,提供高精度采集解決方案: 一、系統設計關鍵要點 ADS1220特性 24位高精度ΔΣ ADC,支持4路單端或2路差分輸入 集成PGA(增益1~128)、基準電壓和可編程電流源 多通道限制:…

百特搭AI低代碼平臺助力企業國際化業務敏捷拓展

在全球化浪潮下&#xff0c;企業揚帆出海或服務全球客戶已成為重要戰略。然而&#xff0c;開拓國際市場面臨多重挑戰&#xff1a;語言文化差異顯著、本地化需求復雜多變、智能化應用需求激增、各國IT基礎設施與合規要求各異。企業亟需一個能夠快速響應、靈活適應&#xff0c;并…

epoll_event數據結構及使用案例詳解

epoll_event 數據結構詳解 在 Linux 的 I/O 多路復用機制 epoll 中&#xff0c;epoll_event 是關鍵的數據結構&#xff0c;用于描述文件描述符&#xff08;fd&#xff09;上的事件和關聯數據。其定義在頭文件 <sys/epoll.h> 中&#xff1a; struct epoll_event {uint32_t…