Go vs Java vs C# 語法對比

暗香殘留發表於2022-02-13

1. 說明

  • 最近在學習Go,在學習的過程中為了加快學習速度、將新知識新增到已有知識體系架構中,總是會拿Go和其他開發語言進行對比,最終進行總結,於是就有了這篇文章。

  • 對於每一個知識點結束時會給出我個人的一些新的體會(即小結),另外我儘量給出引用相關資料,大家可以從源頭進行檢視相關資訊

2. 對比

  • 在進行開發語言知識點對比時儘量做到客觀

  • 對比的角度:基礎語法

  • PS:
      更高層次可以選擇從程式設計正規化方面等進行對比。Go是函數語言程式設計(或者叫指令式程式設計,支援物件導向特性),Java、C#是物件導向程式設計(基於類的物件導向程式設計)

2.1 關鍵字(keywords)

在開發的過程中,為了實現不同的業務或者解決問題,我們需要採用開發語言的各種關鍵字,經常使用的基本已經滿足需求,但是對於那些少量的最好有所瞭解,因為他們可能會提升你的開發效率或者提升效能。共勉!

2.1.1 Go

Go 有以下關鍵字(共25個)

break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var

參考資料

2.1.2 Java

Java 有以下關鍵字(共50個)

abstract continue for new switch
assert*** default goto* package synchronized
boolean do if private this
break double implements protected throw
byte else import public throws
case enum**** instanceof return transient
catch extends int short try
char final interface static void
class finally long strictfp** volatile
const* float native super while

說明

* not used
** added in 1.2
*** added in 1.4
**** added in 5.0

參考資料

2.1.3 C#

C# 有以下關鍵字(共77個),額外還有上下文關鍵字(共42個)

abstract event namespace static
as explicit new string
base extern null struct
bool false object switch
break finally operator this
byte fixed out throw
case float override TRUE
catch for params try
char foreach private typeof
checked goto protected uint
class if public ulong
const implicit readonly unchecked
continue in ref unsafe
decimal int return ushort
default interface sbyte using
delegate internal sealed virtual
do is short void
double lock sizeof volatile
else long stackalloc while
enum

參考資料

2.1.4 小結

從關鍵字數量上來說

Go最少(25)、Java次之(50)、C#最多(77)

從功能上來說

Go:官方對於底層封裝最少,看起來應對的業務場景相對較少,可能各種業務場景都需要自行進行封裝,當然這也和其設計初衷有關,但是和其他語言(例如:C)結合起來進行開發你會感到整個世界都是你的

Java:官方對於底層封裝相對(Go)較多,但是對於應付各種業務場景來說還是顯得不夠(需要自行進行類庫封裝),所以市場上各種輪子比較多(如果能夠深入原理,輕鬆走向架構師)

C#:官方對於底層封裝比較豐富、多樣化,不需要封裝即可應付大多數業務場景(輕鬆進行封裝,可以將物件導向概念發揮到極致),缺點也比較明顯比較容易造成開發人員懶惰、影響創新

總體說明

從關鍵字數量和功能可以看出該語言對於底層的封裝程度,但總體來說開發語言沒有對錯、優劣,在不同的場景選擇合適的開發語言即可

2.2 基本資料型別

思考一個問題:為什麼需要有資料型別?

  • 一些答案:
  • 《Java 程式設計的邏輯》 一書中對於其的解釋是 資料在計算機內部都是二進位制表示的,不方便操作,為了方便運算元據,高階語言引入了資料型別和變數的概念
  • 我自己的理解(不一定正確):

  • 每一種資料型別所佔用的byte/bit是不同的(或者代表意義不同),他們的存在或者組合滿足了各種資料操作場景,進一步滿足了各種業務場景的需要(支援《Java 程式設計的邏輯》所說),便於CPU對記憶體進行操作,同時也便於進行資料儲存(和資料庫資料型別對應)。

2.2.1 Go 基本資料型別

共19個

int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
float32 float64 complex64 complex128 byte rune
bool string

說明

  • byte: alias for uint8 (不可相容漢字)

  • rune: alias for int32, represents a Unicode code point (可相容漢字)

  • string: 底層採用的是byte陣列

參考資料:

2.2.2 Java 基本資料型別

共8個

byte short int long
float double boolean char

說明

  • string: 底層開始採用的是char陣列(java 1.8 及之前版本),後面改為byte陣列(java 1.9 及以後版本)

參考資料

2.2.3 C# 基本資料型別

共18個

byte sbyte
short ushort
int unit nint nuint
long ulong
float double decimal
bool char
object string dynamic

說明

  • 除nint、nuint和dynamic之外,都是.NET型別的別名

  • object、string、dynamic 為引用型別,其他都是值型別

  • string: 底層採用char陣列

參考資料

2.2.4 小結

  • 無論哪一種開發語言,string型別變數值都是不可修改的,底層如採用byte陣列實現將無法支援中文(中文需要3-4個位元組進行儲存),如需支援中文則需要採用其他型別陣列(例如:char,rune)實現

2.3 值型別和引用型別

說值型別和應用型別就不得不講棧和堆

棧:是記憶體的一塊區域,用於存放值型別的的值

堆:也是記憶體的一塊區域,用於存放引用型別的值;但變數也會佔用棧上的記憶體(存放的不是具體資料型別的值,而是一個記憶體地址,其指向堆上的一塊記憶體區域,這片記憶體區域儲存的是對應變數的值)

2.3.1 Go 值型別和引用型別

  • 值型別:包含所有基本資料型別、陣列、結構體

  • 引用型別:其他非值型別(包含:指標、slice切片、管道channel、介面interface、map、函式等)

2.3.2 Java 值型別和引用型別

  • 值型別:byte、short、int、long、float、double、boolean、char

  • 引用型別:其他非值型別

2.3.3 C# 值型別和引用型別

  • 值型別:sbyte、byte、short、ushort、int、uint、long、ulong、uint、nuint、float、double、decimal、bool、char、列舉、結構體、Tuple

  • 引用型別:其他非值型別(class、interface、delegate、record、dynamic、object、string)

參考資料

2.3.4 小結

  • 無論哪一種開發語言,string型別變數值都是不可修改的,不同的語言可能將其歸類設定可能不一致(C#是引用型別,其他是值型別)

  • 數字型別、布林型別、字元(即char,如果有)在三種語言中都為值型別(思考:為什麼?)

2.4 變數

  • 變數 = 變數名 + 資料型別 + 變數值

  • 變數:分為全域性變數(可以簡單理解為:方法外部的變數)和區域性變數(可以簡單理解為:方法內部的變數)

  • 無論是Go、Java、C# 對於變數、方法名稱都區分大小寫

2.5 運算

  • 電腦,也叫作計算機,誕生的最初目的是為了便於計算(算術運算)

  • 運算:分為算術運算、比較運算、邏輯運算

  • 現有計算機只會進行加法運算和邏輯運算,所有其他運算都將會被轉換為這兩種運算

2.5.1 Go 支援運算子

+ & += &= && == != ( )
- -= =
* ^ *= ^= <- > >= { }
/ << /= <<= ++ = := , ;
% >> %= >>= -- ! ... . :
&^ &^=

說明

  • Go、Java、C# 均支援以上運算子

  • Go不支援左面++和--(只支援右面++和--,例如:number++)

2.5.2 Java 支援運算子

=
+ - * / %
++ -- !
== != > >= < <=
&& || ?:
~ << >> >>> & ^ |

2.5.3 C# 支援運算子

  • C# 支援的運算子比較多,官方文件將其分為:算術運算、比較運算、布林邏輯運算、位運算、移位運算、相等運算

  • 具體運算子請檢視相關 資料

2.5.4 小結

  • 不同軟體開發語言對於運算子的支援是不同的(也有一些是其定製化的)

  • 三種開發語言中,C# 對於底層的封裝更多(語法更加豐富)

參考資料

2.6 流程控制語句

  • 流程控制有2種:條件判斷和迴圈

  • 一般軟體開發語言都會實現這2種流程控制,否則只能執行簡單的自上而下(或者自下而上)流程

  • 不同流程控制的組合可以解決各種複雜疑難問題

  • 兩種流程控制

    1. 條件判斷
      if
      if/else
      if/else if/else
      switch
    1. 迴圈
      while
      do/while
      for
      foreach
  • 說明

  • Go 中switch語句更加強大,可以實現if/else if/else效果。(PS:經 “吉良吉影” 大佬的指出發現從C# 8.0開始,C#也支援類似功能了,請檢視資料switch expressionconstant pattern

  • Go 中沒有while、do/while,但可以使用for實現類似效果(for迴圈體中實現自增、條件判斷、break效果)

  • Go 中沒有foreach,但是可以通過for range實現類似效果,並且功能更加強大

2.7 函式(或方法)和類

  • 函式

  • Go 沒有方法過載,同一包內不允許出現相同方法名稱(排除首字母小寫的方法名稱,因為首字母小寫的方法只允許當前檔案內部訪問)

  • Go 採用函數語言程式設計,函式是一等公民,也是一種資料型別,可以直接賦值給變數。

  • Go 沒有try catch,但可以使用 defer/recover 來處理報錯資訊

  • Go 和 C# 均支援同時返回多個引數(PS:Java不支援 也有可能我沒有發現

  • C# 方法引數可以有預設值(非型別預設值),Go、Java 則不允許

  • 內部丟擲錯誤:Go、Java、C# 都允許丟擲任意錯誤,Java 則可以在定義方法時指定哪些錯誤必須要處理

  • Go、Java、C# 均可以實現匿名函式

  • Go、Java、C# 均使用main函式作為程式入口方法

  • Go 無類的定義

  • Java、C# 都實現了基於類的物件導向,都將類作為一等公民,目前C#語法更為豐富和強大。抽象類、介面的靈活使用可以讓你的程式碼非常靈活、業務發生變化時的改動更少

  • Java、C# 具有匿名類

  • C# 類建構函式引數支援預設值,Java不支援

  • Java、C# 的訪問修飾符區別比較大(特別是protected),C# 更豐富

  • Java 中程式碼是通過包來組織的,C#是通過專案(例如:類庫)組織的

說明

  • Go、Java、C# 函式名稱、類名稱 都區分大小寫,對於命名規範要求也類似
  • 泛型

  • C# 對於泛型支援較為完善(效能最好,因為是複製一份程式碼)

  • Java 是一種偽泛型(實際為Object型別)

  • Go 不支援泛型,但是可以通過 interface 來支援類似泛型的操作

總結

  • 學習方法:對比的最終目的是為了更加快速的建立知識體系、學習相關語言

  • 硬體限制:任何開發語言都逃不開硬體對於軟體的限制

  • 發展的眼光看待問題:Go、Java、C# 都在蓬勃發展,語法內容可能會有所變化,可以先建立一個知識樹,有變化時再去更新知識樹

相關文章