91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

golang中的不可變類型有哪些

發布時間:2020-06-16 10:33:50 來源:億速云 閱讀:243 作者:Leah 欄目:編程語言

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

Golang 中的不變性

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

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

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

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

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

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

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, 構造函數 NewAmount以及 GetValue 方法用于 Amount類型. 一旦 NewAmount 函數創建了 Amount 結構, 就無法更改它. 因此它從包的外部來說是不可變的 (盡管在 go 2 中有 更改此內容的建議, 但 go 1 中沒有創建不變結構的方法). 此外沒有處于無效狀態 (在這種情況下為負數) 的 Amount 類型的變量, 因為創建它們的唯一方法已經對此進行了驗證. 我們可以從另一個包中調用它:

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

在函數中使用值拷貝替代指針

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

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

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

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

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
}

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

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),其包含了改變后的字段。

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

減少全局或外部狀態中的依賴性

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

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

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
}

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

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

看完上述內容,你們對golang中的不可變類型有進一步的了解嗎?如果還想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

孝义市| 大竹县| 塘沽区| 黑山县| 定边县| 加查县| 德化县| 柘城县| 彭泽县| 蕉岭县| 南木林县| 阿勒泰市| 封丘县| 普安县| 金昌市| 兴宁市| 象州县| 清涧县| 刚察县| 汾西县| 姜堰市| 英德市| 农安县| 茌平县| 通州市| 环江| 临武县| 上犹县| 五原县| 图木舒克市| 正阳县| 神池县| 宜阳县| 城固县| 胶州市| 赫章县| 太原市| 桐城市| 贵州省| 新和县| 黄骅市|