聞道Go語言,6月齡必知必會

2022-10-25 21:03:31

大家好,我是馬甲哥,

學習新知識, 我的策略是模仿-->歸納--->舉一反三,

在同程倒騰Go語言一年有餘,本次記錄《聞道Go語言,6月齡必知必會》,形式是同我的主力語言C#做姿勢對比。

1. 宏觀預覽

1.1 常見結構對比

某些不一定完全對標,實現方式,側重點略點差異。

go語言 --- C#語言 ---
module assembly
pkg go get github.com/thoas/go-funk package Install-Package Masuit.Tools.Core
struct class
pointer reference
net/http web腳手架、 httpclient ASP.NETCore、httpclient
net/http/DefaultServeMux ASP.NETCore腳手架路由
goroutine 非同步任務、 async/await
channel CSP TPL data flow CSP模型在C#並非主流
context timeout、 cancellation-token

1.2 存取級別

go語言使用[首字母大小]寫來體現公開/私有, 應用到package struct function;
C#顯式使用關鍵字來體現。

1.3 型別初始化

go語言有兩初始化的內建關鍵字

  • new : 用於分配記憶體(帶記憶體零值),返回指標 new(int), new(Cat)
  • make : 只用於slice、map、 channel 參照型別的初始化

C#基礎型別使用字面量, 參照型別使用new關鍵字

2. 編碼邏輯結構

2.1 順序

這沒什麼好說的,都是至上而下, 遇到函數進函數堆疊。
go語言每行程式碼後不需要加分號;C#語言每行程式碼後需要加分號。
go對於括號的使用有要求: 斜對稱, C#無要求。

2.2 分支

if --- elseif --- else

go和C#語言基本是一樣的

- go語言else if、 else 不允許換行,C#對此無要求。
- C#要求[使用括號包圍]條件判斷語句。
switch -- case [break]

- go語言case語句預設都加上了break,加不加都一樣,滿足當前case,執行完就會跳出當前switch, 不會一直case下去;
- C#語言執行分支需要主動break, 若沒有break,表示共用可用的執行體。

2.3 迴圈

  • go語言只有for迴圈,C#還有while, do while

使用for來體現while/do while

3. 物件導向

封裝 抽象 繼承 多型

同樣是物件導向程式語言,go用結構體來體現,C#常用類來體現。

封裝

通常go語言基於結構體、接收者函數來[封裝/提煉]事物和行為。

  • 接收者函數分為: 值接收者函數、指標接收者函數。

  • 兩種都能體現封裝, 但[指標接收者函數]內的操作會體現到入參。

  • 不管是值,還是指標,都能呼叫指標接收者函數/值物件接受者函數,效果還是如上一點一致。

C# 顯式使用Class struct等結構來封裝資料和行為。

抽象 + 繼承

go語言沒有抽象函數、抽象類的說法,有介面抽象 和父子類繼承關係。

介面將具有共性的方法放在一起,其他任何型別只要實現了這些方法就是實現了介面,俗稱鴨子模式。

C#具備語意化的繼承/抽象/多型, 顯式繼承。

4. 指標 vs 參照

指標指向一個記憶體地址; 參照指向記憶體中某個物件。

一般認為go是C語言的家族,但是go的指標弱化了C語言的指標操作,go指標的作用僅操作其指向的物件, 不能基於地址這個概念做指標移位, 也不能基於地址這個概念做型別轉化。

A value of a pointer type whose base type is T can only store the addresses of values of type T.

go的指標簡化了指標的使用,減少了指標出錯的概率。

參照可看做是指標的抽象,也基於code safe的理由,不能在參照上做算術運算和低階別的取巧。

從這個意義上看,C#的參照等價於go的指標, 都是型別安全的指標


另一方面, 兩種語言都提供了對記憶體進行任意讀寫的姿勢(非程式碼安全)。

go的unsafe.Pointer本質是一個int指標。

type Pointer *ArbitraryType
type ArbitraryType int

C# unsafe關鍵字可用在函數、屬性、建構函式、程式碼塊。

5. goroutine vs async-await

表象
  • goroutine由go的原生函數生成,只要前面加上go的語法關鍵字go(可以有形參,返回值會被忽略)。
  • await/async語法糖,簡化了非同步程式設計的姿勢;實際會被編譯器編譯成一個狀態機。

goroutine是在runtime級別深度內建, async-await是在CLR之上基於C#語言構建。

核心對比

首先要知道: 執行緒是cpu排程的基本單位,不管是goroutine還是async-wait機制都是在嘗試提高[cpu排程執行緒的效率]。

  • go在os核心執行緒之上,原生支援了輕量級的使用者態執行緒goroutine,堆疊很小,開銷很小,(存在一個使用者態邏輯處理器給執行緒投喂goroutine)。

  • C#編譯器生成的狀態機,轉化並管控基於執行緒池執行緒的主調任務、非同步任務、後繼任務。

兩者支援並行的思路有明顯差異:

go: 核心態執行緒切換開銷大,故原生提供使用者態執行緒,開銷極小,天然支援高並行,且不輕易墜落到核心態, 是一個革命派的思路。

C#:async-await針對執行緒做輾轉騰挪,高效利用, 是一個改良派的思路。

非同步

都具備非同步的能力,go語言沒有await的概念,goroutine在等待通道讀操作時[掛起自身,並將OS執行緒釋放給另一個goroutine], 跟C#執行時遇到await關鍵字的行為效果是一樣的。

推薦附加閱讀

本文限於篇幅,只記錄了go語言和C#語言的入門6月齡的核心差異點和重難點,高手繞道, 後續會不斷完善, 請有心人持續關注左下角原文, 如果能點贊更是莫大的鼓勵。