首頁  >  文章  >  後端開發  >  Go 的嬰兒學步

Go 的嬰兒學步

WBOY
WBOY原創
2024-08-05 19:28:13380瀏覽

Baby steps with Go

我決定在我的旅程中嘗試 Go,以學習一門對我的職業和興趣有用的新語言。這次我嘗試了Go。我認為第一印象非常好。

這不是一個導遊,可以說,不是為除了我自己以外的任何人編寫的,作為一些個人提醒。

我為自己做了一個小項目,名為 Os-Release-Q 。我的目的是能夠在我管理的任何系統上都有一個二進位文件,這樣我就可以準確地列印我需要的信息,而無需對其進行解析或eye-grep。

第一個障礙:進口

網路上搜尋很多關於導入別人的包的內容,但很少談到組織自己的程式碼。甚至文件也關注 go get 而不是關注點分離。

我在每種語言中都會遇到這個障礙,因為每種語言對於如何實現它都有自己獨特的哲學,以及每種語言有或強加的限制。

在我學習基礎知識的所有活動中,由於主要是Python背景,將我的程式碼分成多個檔案是我花了最長的時間才得到答案的事情。總而言之,我發現了以下內容:

  • 頂層需要一個 go.mod 宣告模組 module-name
  • 然後我可以在頂層設定一個 src/ 目錄,並在其中放置我的 main 函數,並在頂部設定一個套件 main 聲明
  • 將程式碼放入其他檔案中非常簡單,只需建立一個帶有包主聲明的檔案(如 src/others.go)即可。
  • 所有函數和變數都可以直接在 main 套件的任何其他檔案中使用,但需要在 go build FILES 呼叫中明確聲明這些檔案

對於本機子模組,子模組必須駐留在資料夾中。它可以宣告一個套件 submodule-name .

假設它在 src/submod/ 中,主要實現者在 src/submod/submod.go 中。在 main.go 中,我們導入「module-name/src/submod」(模組名稱是從 go.mod 中提取的)。然後我們可以呼叫 submod.SomeFunction().

我們注意到,子模組函數僅適用於名稱以大寫字母開頭的導入者。所以不要做 submod.myFunction() - 它必須是 submod.MyFunction().

關於子模組和導入肯定還有其他考慮因素,但就保持程式碼組織和隔離而言,這是必不可少的。

為了保持理智,我試圖只使用一個檔案來聲明 package main,並將其餘部分隔離到子模組中 - 這些會自動導入,無需在 go build FILES 檔案清單中聲明。

執行基本任務

在解決了 Go 的特殊性之後,其餘的事情就很容易解決了。對於每個基本任務,當然都有一個 StackOverflow 條目,或一個 GoByExample.com 頁面,更基本的是 Go 語言參考。

  • 字串處理是透過 strings 套件完成的
  • 陣列處理有許多本機函數,其中 base_array =append(base_array, item1, item2) 模式 - 它也適用於透過append(base, other_array...) 用另一個陣列的值擴展一個陣列
  • 錯誤處理通常是透過傳遞錯誤物件來完成的,但不一定。
  • 存在一個「日誌」庫,用於方便的預先配置無幹擾日誌。它包括一個 log.Fatal(message) 調用,該調用會記錄錯誤並立即退出。
  • 透過「os/exec」函式庫使用 exec.Command(base, args...) 模式呼叫子程序很容易

兩個特別常見的任務值得擁有自己的段落。

錯誤處理

基本錯誤處理通常被認為很麻煩,實際上需要在控制流程中處理錯誤。對於來自 try/catch 工作流程的程式設計師來說,這可能是令人厭惡的,但在可能發生的情況下處理問題並不是那麼糟糕。

// explicit return item `err` forces us to be aware of it
// but having the ability to check it in the same breath is not so bad
if result, err := someCall(); err != nil {
    log.Fatal("Sorry.")
}

// Equally valid is
/*
result, err := someCall()
if err != nil {
    log.Fatal("Sorry")
}
*/

fmt.Println(result)

比較try/catch方式

try:
    result = someCall()
    print(result)
except:
    print("Sorry") # a little divorced from potential origin of error
    sys.exit(1)

參數解析

我不禁覺得flags函式庫的實作有點半生不熟。顯然,考慮到它以目前的形式生存下來,人們已經習慣了它並且對此表示滿意。

呼叫程式 -flag arg1 arg2 為我們提供了 flag 設定為執行的切換,positionals := flags.Args() 傳回 ["arg1", "arg2"] 陣列

但是呼叫程式arg1 arg2 -flag 不會切換-flags 應該執行的任何操作,而是給出位置作為["arg1", "arg2", "-flag"] 其中標誌未解析。

這對於傳遞像程式 colorize ls -l 這樣的子呼叫可能很有用,其中 ls -l 按字面意思傳遞 - 這樣我就可以看到一個用例。

只是大多數程式都允許在位置項目周圍的任何地方使用標誌參數。 ls dir1/ -l dir2/ 與 ls -l dir1/ dir2/ 相同,這是一個適用於絕大多數 Unix 和 Linux 指令的約定。

這可能只是需要習慣的事情 - 並且值得呼籲。

Go 的目的和用例

除了檔案匯入範例之外,我發現實作我的基本應用程式非常容易。我做錯的任何事情都感覺相當明顯,而且這些錯誤是有意義的。確實感覺我可以專注於「把事情做好」。

從我迄今為止微薄的使用量來看,並考慮到我的具體需求,我可以看到

  • 易於上手
  • 編譯的二進位文件,無運行時依賴
  • 有類型的簡單語言是 shell 腳本的一個進步
  • 據稱簡單的多處理支援

我認為使用稀疏類型而不是物件和繼承會是一個障礙,但到目前為止還不錯。我在其他語言中不需要它們,所以我想當我開始定義介面和類型時,感覺就像是 Lua 和 bash 的一個進步。我希望。

我想探索編譯為本機語言的原因之一是能夠產生可以輕鬆分流的二進位文件,而不需要依賴存在的特定版本的執行時間。

一位同事最近沮喪地走到我的辦公桌前,試圖解決將 Java 17 移植到基於 Debian 10 的舊 Node 基礎鏡像上的問題。他要么必須升級Node 版本以獲得更新的基礎鏡像,使用新的Debian 基礎鏡像並手動安裝和配置Node,要么在互聯網上搜索由“好人知道”託管的自定義存儲庫以獲得“好人知道” -if -hacked Java 17 將在Debian 10 上運行。

如果部署的軟體沒有這種相互衝突的運行時依賴關係,該有多容易......

從維運的角度來看,我覺得我能感受到的一大收穫是:我可以輕鬆編寫程式碼,並建立一個ELF 二進位文件,然後部署在「任意系統X」上,而不必與確保給定運行時的正確版本到位,並管理衝突的依賴項。

我確信還有其他好處,而且我聽過很多關於Go 中多線程和多處理的易用性的說法,我確實打算製作一個迷你項目來探索這一點,作為下一步-可能會監聽多個通道上的輸入,並執行一些基本任務作為回應。我在之前的一些測試自動化任務中已經有過這樣的用例,所以此時它對我來說並不陌生。

以上是Go 的嬰兒學步的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn