Golang自學系列


為什么會有這個系列?

因為我要往架構方向靠攏啊。
關於架構,其實架構的書我看了《架構整潔之道》,也有《實現驅動領域設計》。但是我感覺明顯還不夠,所以我在極客時間買了一個架構相關的專欄,這個專欄寫的編程語言是 go,為了更好的學習與理解,所以才有這個系列。

我在使用vscode進行go編程時,總會顯示一下警告

type Service struct {
		a *ClassName
}
exported type Service should have comment or be unexported

這是因為你安裝插件 gopls 對代碼會有一些規則。即如果你定一個 變量/類 時,如果開頭是大寫字母,那么編輯器就會檢測出你沒有針對這個 變量/類 進行注釋。這個時候有兩種選擇

  1. 將大寫字母改成小寫字母 service
  2. 進行特定格式注釋,如上面注釋就是這樣//Service 服務類

其實除了這個還有一種做法,直接設置vscod的相關檢測的屬性"go.lintFlags":["--disable=all"],這樣就不用寫那些煩人的注釋啦。

golang 的編碼習慣有個很有意思,就是它的所有變量、方法、類 等等在代碼的末句全都不需要打分號,就算你打了分號,編輯器一樣也會給你自動省略

怎么導入第三方庫?

直接在官方倉庫地址選擇自己要導入的模塊,地址見:https://pkg.go.dev

import ("moduleName")

但是我當初這么做的時候,發現雖然編譯器沒有檢測到錯誤,但是在引用 module 的 api 時,沒有智能提示。后來發現跟 nuget 是一樣的,有快捷鍵導入 module: shift + command + p 然后選擇 Go: Add Import 選中你本地 clone 下來的第三方類庫。但是這里有一個疑問,難道要每次下載源代碼嗎?而是不能夠直接下載一個類似 dll 的可執行的 “微文件” 么。講道理是肯定有的,不可能一個項目發布出去,還把人家的源代碼發不出去的。這個之后弄到發布的時候在回過頭來查資料吧

錯誤1: expected ';', found f 這個是不同編輯器的編碼問題,拿我現在用的 vscode 為例,我新建的 go 項目的默認編碼是 LF/CRLF,切換成 CRLF/LF 。注意,如果切換的時候發現還是報同樣的錯誤,那極有可能是 vscode 沒有反應過來,只要在當前頁面隨便輸個空格在保存即可。

接下來就是各種變量函數的基本用法介紹了

null 值:golong 用 nil 代表 null,這個很特別啊,大多數語言都是 null

定義類:用 type 關鍵字 type ClassName struct{ someField int}

申明變量:var scopeVar = "string" 我試了一下,這種顯示寫法也行 var scopeVar string = ""

但是有這么一種寫法 localVar := "",也很有趣,我嘗試了一下,這個好像只能在方法里面寫(就相當於 var localVar string = ""),這種寫法提升到 “全局” 則不行。

golong 具有指針概念

指針保存的是變量的內存地址。比如 var p *int p 表示的是整形的地址,其零值是 nil

這個跟 c++ 的指針是一樣的,比較復雜,當時上大學的我上課上到這個地方的時候很懵,什么“指針”,“指針的引用”,“指針的指針”,“ * ”,“ & ” 等總是搞不清楚。在用 vc++ 6.0 時代下,編寫代碼沒有任何提示,簡直是難如登天。

但是現在時代不同啦,ide/編輯器 可以自動幫你做正確的選擇。這次偶然的機會學習 golang,不過我還是有必要把這地方的知識弄清楚。

首先看下面代碼,我把注釋寫在邊上

var p *int	// 變量 p 代表是整形的內存地址
i := 11	// 就一般的變量賦值
p = &i	// 給內存地址指針變量 p 賦值 11 的指針變量
*p = 1	// p 地址的值賦值為 1

第二行我就不解釋了。

第一行代碼就是定義一個指向整形的內存地址的變量 p。

第三行代碼表示你要給一個整形的地址賦值,那么肯定不是直接賦值一個整數 i,而是這個變量 i 指向的整數的地址 &i。其實可以理解為 i 的一個引用。

第四行我要直接給 p 指針指向的地址具體的值,那就是我們之前說的 “指針的指針:*p = 1”。

函數申明

函數在 golang 里面同 js 是一樣 —— 一等公民。也就是你無論寫在哪里,它都是可以在當前域是有效,可以引用的。

函數申明分兩種

  1. 無返回值:func SomeMethod() {}
    1. 帶參數:func SomeMethod(a int) {}
  2. 有返回值:func SomeMethodAndReturn() ReturnValue {}

函數這里面有個好玩的約定:

  • 函數名首字母是小寫就是 private 私有方法
  • 函數名首字母是大寫則是 public 共有方法

我們還可以定一個函數類(函數類就相當於 C# 的委托,委托對於 CLR 而言就是一個含有這么一個函數的類,也可以當做 Java 中的內部類處理)。實例代碼如下所示

type delegateFunc func(string)	// 定一個委托
func serve(msg string){
  fmt.Printf(msg)
}
func main(){
  d := delegateFunc(serve)	// 把函數當作參數傳遞
  d("marson shine")
}

方法定義

方法的定義跟函數很像: func (type類型參數) MethodName(parameters) ReturnValue {}

先來看官網對方法的定義

一個 type 指定的類型可以關聯方法集。一個接口類型的方法集是其接口。任何類型 T 的方法集,由它作為接收器接收所有方法。對應的指針類型 *T 的方法集是由接收器 *T 或者是 T 申明的方法集(那也就說,它包含了 T 的所有方法集)。更多的規則運用在包含那些匿名字段的結構(struct)上。任何類型都有空的方法集。在一個方法集中,每個方法必須有一個唯一的不為空的名稱。

我們舉個例子來說明:

func (typeName ClassName) MethodName(parameter string) string {

}

這里我們定義了一個方法,指定的接收器就是 ClassName 類型,即我們得先有個接收器,才能有這個方法集 MethodName

type ClassName struct {
		userName string
}

那么這個時候我就可以出實話一個 ClassName,然后就可以調用方法 MethodName 了。

對於上面的方法定義,其實還有一種寫法是這樣的:

func (typeName *ClassName) MethodName(parameter string) string {

}

這個我翻閱了下資料,發現這個還是很有趣的,這個跟編譯器以及 golang 本身的 “函數式編程” 的特性有關。函數式有個很重要的特征,就是 “無狀態” 的。舉個例子,我新建一個函數,這個函數本身是無狀態的,只要你傳入的參數不變,那么這個函數得到的值就是恆定值。我們拿之前的方法為例子 func (typeName ClassName) MethodName(parameter string) string {} 這個就是說你無法更改 typeName 這個值,它是不變量的。你只能在這個函數領域下更改,一旦這個方法返回(指定的棧地址)則傳入的 typeName 就還是之前的狀態。如果你要像 C# 一樣傳遞一個引用,在局部更改返回后,這個引用對象同樣也會更改的話,改怎么實現呢?也很簡單,只要在原來的基礎之上加個 “ * ”,也就是上面的寫法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM