golang中的不可變類型有哪些-創(chuàng)新互聯(lián)

golang中的不可變類型有哪些?可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據(jù)這篇文章可以有所收獲。

創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設、高性價比平遙網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式平遙網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設找我們,業(yè)務覆蓋平遙地區(qū)。費用合理售后完善,10余年實體公司更值得信賴。

Golang 中的不變性

如何利用不變性來增強你的 Golang 應用程序的可讀性和穩(wěn)定性

不變性的概念非常簡單. 創(chuàng)建對象 (或結構體) 后, 將永遠無法更改它. 這是一成不變的. 盡管這個概念看起來很簡單, 但使用它或從中受益并不那么容易.

正如計算機科學 (和生活) 中的大多數(shù)事物一樣, 有許多種方法可以達到相同的結果, 就不變性而言, 兩者沒有什么不同. 您應該把它看做是工具包中的一個工具, 并使用在適用的問題場景上. 關于不變性的一個非常好的用例是在您進行并發(fā)編程時. Golang 在設計時就考慮了并發(fā)性, 因此在 go 中使用并發(fā)非常普遍.

無論您使用哪種范例都可以通過以下方法在 Golang 中使用一些不變性概念來使代碼更具可讀性和穩(wěn)定性.

僅導出結構體的功能, 而不導出其字段

這與封裝類似. 使用非導出字段創(chuàng)建結構, 僅導出作用的函數(shù). 由于您只對那些結構的行為感興趣, 因此該技術對接口非常有用. 這項技術的另一個很好的補充是將創(chuàng)建函數(shù) (或構造函數(shù)) 添加并導出到您的結構中. 這樣您可以確保該結構的狀態(tài)始終有效. 始終保持有效狀態(tài)可以使代碼更加可靠, 因為您不必繼續(xù)處理要對該結構進行的每個操作的無效狀態(tài). 下面是一個非?;镜氖纠?

package amounts

import "errors"

type Amount struct {
    value int
}

func NewAmount(value int) (Amount, error) {
    if value < 0 {
        return Amount{}, errors.New("Invalid amount")
    }

    return Amount{value: value}, nil
}

func (a Amount) GetValue() int {
    return a.value
}

在此程序包中, 我們定義了 Amount 類型, 具有未導出的字段 value, 構造函數(shù) NewAmount以及 GetValue 方法用于 Amount類型. 一旦 NewAmount 函數(shù)創(chuàng)建了 Amount 結構, 就無法更改它. 因此它從包的外部來說是不可變的 (盡管在 go 2 中有 更改此內容的建議, 但 go 1 中沒有創(chuàng)建不變結構的方法). 此外沒有處于無效狀態(tài) (在這種情況下為負數(shù)) 的 Amount 類型的變量, 因為創(chuàng)建它們的唯一方法已經(jīng)對此進行了驗證. 我們可以從另一個包中調用它:

a, err := amounts.NewAmount(10)
*// 處理錯誤
*log.Println(a.GetValue())

在函數(shù)中使用值拷貝替代指針

最基本的概念是在創(chuàng)建一個對象(或者結構體)后,再也不去改變它。但是我們經(jīng)常在實體狀態(tài)很重要的應用上工作。不過,程序中實體狀態(tài)和實體內部表示是不同的。在使用不變性時,我們仍然可以給實體賦予多個狀態(tài)。這意味著已創(chuàng)建的結構體不會改變,但是它的副本會改變。這并不意味著我們需要手動實現(xiàn)復制結構體中每個字段的功能。

相反地,當調用函數(shù)時我們可以依賴 Go 語言復制值的本機行為。對于任意一個會改變實體狀態(tài)的操作,我們可以創(chuàng)建一個用來接收結構體作為參數(shù)(或者作為函數(shù)接收器)的函數(shù),在執(zhí)行完畢之后返回改變后的版本。這是一項非常強大的技術,因為你能夠改變副本上的任何內容,而無需更改函數(shù)調用者作為參數(shù)傳遞的變量。這意味著沒有副作用和可預測的行為。如果相同的結構體被傳遞給并發(fā)函數(shù),每個結構體都會接收到它的副本,而不是指向它的指針。

當你在使用切片功能時,你會看到此行為應用于 [append](https://golang.org/pkg/builtin/#append) 函數(shù)

回到我們的例子中,讓我們實現(xiàn) Account 類型,它包含了
Amount 類型的 balance 字段。同時,我們添加 DepositWithdraw 方法來改變 Account 實體的狀態(tài)。

package accounts

import (
    "errors"
    "my-package/amounts"
)

type Account struct {
    balance amounts.Amount
}

func NewEmptyAccount() Account {
    amount, _ := amounts.NewAmount(0)
    return NewAccount(amount)
}

func NewAccount(amount amounts.Amount) Account {
    return Account{balance: amount}
}

func (acc Account) Deposit(amount amounts.Amount) Account {
    newAmount, _ := amounts.NewAmount(acc.balance.GetValue() + amount.GetValue())
    acc.balance = newAmount
    return acc
}

func (acc Account) Withdraw(amount amounts.Amount) (Account, error) {
    newAmount, err := amounts.NewAmount(acc.balance.GetValue() - amount.GetValue())
    if err != nil {
        return acc, errors.New("Insuficient funds")
    }
    acc.balance = newAmount
    return acc, nil
}

如果你檢查我們創(chuàng)建的方法,他們會覺得我們事實上改變了作為函數(shù)接收器的 Account 結構的狀態(tài)。由于我們沒有使用指針,情況并非如此,由于結構體的副本作為這些函數(shù)的接收器來傳遞,我們將更改只在函數(shù)作用域內有效的副本,然后返回它。這是在另一個包中調用它的示例:

a, err := amounts.NewAmount(10)
acc := accounts.NewEmptyAccount()
acc2 := acc.Deposit(a)
log.Println(acc.GetBalance())
log.Println(acc2.GetBalance())

命令行上的結果會是這樣的:

2020/06/03 22:22:40 {0}
2020/06/03 22:22:40 {10}

如你所見,盡管通過變量 acc 調用了 Deposit 方法,但實際上變量并沒有改變,它返回了新的  Account 副本(分配給 acc2),其包含了改變后的字段。

使用指針具有優(yōu)于復制值的優(yōu)點,特別是如果您的結構很大時,在復制時可能會導致性能問題,但是您應始終問自己是否值得,不要嘗試過早地優(yōu)化代碼。尤其是在使用并發(fā)時。您可能會在一些糟糕的情況下結束。

減少全局或外部狀態(tài)中的依賴性

不變性不僅可以應用于結構,還可以應用于函數(shù)。如果我們用相同的參數(shù)兩次執(zhí)行相同的函數(shù),我們應該收到相同的結果,對嗎?好吧,如果我們依賴于外部狀態(tài)或全局變量,則可能并非總是如此。最好避免這種情況。有幾種方法可以實現(xiàn)這一目標。

如果您在函數(shù)內部使用共享的全局變量,請考慮將該值作為參數(shù)傳遞,而不是直接在函數(shù)內部使用。 那會使您的函數(shù)更可預測,也更易于測試。整個代碼的可讀性也會更容易,其他人也將會了解到值可能會影響函數(shù)行為,因為它是一個參數(shù),而這就是參數(shù)的用途。 這里有一個例子:

package main

import (
    "fmt"
    "time"
)

var rand int = 0

func main() {
    rand = time.Now().Second() + 1
    fmt.Println(sum(1, 2))
}

func sum(a, b int) int {
    return a + b + rand
}

這個函數(shù) sum 使用全局變量作為自己計算的一部分。 從函數(shù)簽名來看這不是很清楚。 更好的方法是將rand變量作為參數(shù)傳遞。 因此該函數(shù)看起來應該像這樣:

func sum(a, b, rand **int**) **int** {
   return a + b + rand
}

看完上述內容,你們對golang中的不可變類型有進一步的了解嗎?如果還想了解更多相關內容,歡迎關注創(chuàng)新互聯(lián)成都網(wǎng)站設計公司行業(yè)資訊頻道,感謝各位的閱讀。

另外有需要云服務器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內外云服務器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務器、裸金屬服務器、高防服務器、香港服務器、美國服務器、虛擬主機、免備案服務器”等云主機租用服務以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應用場景需求。

當前題目:golang中的不可變類型有哪些-創(chuàng)新互聯(lián)
分享地址:http://www.muchs.cn/article34/pejse.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站建設、用戶體驗服務器托管、電子商務、全網(wǎng)營銷推廣品牌網(wǎng)站設計

廣告

聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設