検索
ホームページバックエンド開発GolangGoの不変型について詳しく解説

Goの不変型について詳しく解説

Jun 15, 2020 pm 06:01 PM
gogolang

Goの不変型について詳しく解説

Golang における不変性

不変性を利用して Golang アプリケーションの可読性と安定性を向上させる方法

不変性の概念は非常に単純です。オブジェクト (または構造体) は一度作成されると、決して変更できません。不変です。概念は単純に見えますが、それを使用したり、その恩恵を受けるのはそれほど簡単ではありません。

コンピューター サイエンス (および人生) のほとんどのことと同様、同じ結果を達成する方法はたくさんあり、不変性の点では違いはありません。これはツールキット内のツールであり、適用可能なもので使用されるものと考える必要があります。問題のシナリオ。不変性の非常に良い使用例は、同時プログラミングを行っているときです。Golang は同時実行を念頭に置いて設計されているため、Go で同時実行を使用することは非常に一般的です。

どのパラダイムを使用するかにかかわらず、ここにいくつかありますGolang で不変性の概念を使用して、コードをより読みやすく安定させる方法。

構造体のフィールドをエクスポートせずに、構造体の機能のみをエクスポートします。

これは次のようなものです。カプセル化。エクスポートされていないフィールドを含む構造体を作成し、機能する関数のみをエクスポートします。これらの構造体の動作のみに関心があるため、この手法はインターフェイスに非常に役立ちます。この手法に追加するもう 1 つの良い方法は、構造体に関数 (またはコンストラクター) を作成します。こうすることで、構造体の状態が常に有効であることを保証できます。常に有効のままです。操作のたびに無効な状態を処理し続ける必要がないため、コードの信頼性が高まります。非常に基本的な例を示します:

package amounts

import "errors"

type Amount struct {
    value int
}

func NewAmount(value int) (Amount, error) {
    if value <p>このパッケージでは、<code>Amount</code> 型を定義し、エクスポートされていないフィールド <code>value</code>、コンストラクター ## を持ちます。 <code>Amount</code> タイプの #NewAmount<code> および </code>GetValue<code> メソッド </code>NewAmount<code> 関数は </code>Amount<code> 構造を作成しますが、これは変更できません。したがって、パッケージの外部からは不変です (ただし、go 2 ではこれを変更する提案がありますが、go 1 では不変の構造を作成する方法はありません)。さらに、タイプ </code>Amount<code> の変数はありません。無効な状態 (この場合は負) です。これを作成する唯一の方法が既に検証済みであるため、別のパッケージから呼び出すことができます: </code></p><pre class="brush:php;toolbar:false">a, err := amounts.NewAmount(10)
*// 处理错误
*log.Println(a.GetValue())

関数内のポインターの代わりに値のコピーを使用します

最も基本的な概念は、オブジェクト (または構造体) を作成し、それを再度変更しないことです。しかし、私たちはエンティティの状態が重要なアプリケーションに取り組むことがよくあります。ただし、エンティティの状態とプログラム内のエンティティの内部表現は異なります。不変性を使用する場合でも、エンティティに複数の状態を割り当てることができます。これは、作成された構造は変更されませんが、そのコピーは変更されることを意味します。これは、構造内の各フィールドをコピーする関数を手動で実装する必要があるという意味ではありません。

代わりに、関数を呼び出すときに値をコピーするという Go 言語のネイティブ動作に依存できます。エンティティの状態を変更する操作では、構造体をパラメータとして (または関数レシーバーとして) 受け取り、実行後に変更されたバージョンを返す関数を作成できます。これは、関数の呼び出し元によって引数として渡された変数を変更せずに、コピー上のあらゆるものを変更できるため、非常に強力な手法です。これは、副作用がなく、動作が予測可能であることを意味します。同じ構造体が並行関数に渡される場合、各構造体はその構造体へのポインターではなく、そのコピーを受け取ります。

スライス関数を使用している場合、この動作が

[append](https://golang.org/pkg/builtin/#append) 関数

例に戻って、

Amount 型の
balance フィールドを含む Account 型を実装しましょう。同時に、Deposit メソッドと Withdraw メソッドを追加して、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 に割り当てられている) の新しいコピーが返されます。分野。 <p>使用指针具有优于复制值的优点,特别是如果您的结构很大时,在复制时可能会导致性能问题,但是您应始终问自己是否值得,不要尝试过早地优化代码。尤其是在使用并发时。您可能会在一些糟糕的情况下结束。</p> <h2 id="span-style-font-size-px-减少全局或外部状态中的依赖性-span"><span style="font-size: 16px;">减少全局或外部状态中的依赖性</span></h2> <p>不变性不仅可以应用于结构,还可以应用于函数。如果我们用相同的参数两次执行相同的函数,我们应该收到相同的结果,对吗?好吧,如果我们依赖于外部状态或全局变量,则可能并非总是如此。最好避免这种情况。有几种方法可以实现这一目标。</p> <p>如果您在函数内部使用共享的全局变量,请考虑将该值作为参数传递,而不是直接在函数内部使用。 那会使您的函数更可预测,也更易于测试。整个代码的可读性也会更容易,其他人也将会了解到值可能会影响函数行为,因为它是一个参数,而这就是参数的用途。 这里有一个例子:</p> <pre class="brush:php;toolbar:false">package main import (     &quot;fmt&quot;     &quot;time&quot; ) 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 }</pre> <p>这个函数 <code>sum 使用全局变量作为自己计算的一部分。 从函数签名来看这不是很清楚。 更好的方法是将rand变量作为参数传递。 因此该函数看起来应该像这样:

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

  推荐教程:《Go教程

以上がGoの不変型について詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事はlearnkuで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
init機能と副作用:初期化と保守性のバランスinit機能と副作用:初期化と保守性のバランスApr 26, 2025 am 12:23 AM

抑制性を促進するために、抑制可能:1)エフェクスを最小化することを最小化します

ゴーを始めましょう:初心者のガイドゴーを始めましょう:初心者のガイドApr 26, 2025 am 12:21 AM

goisidealforforbeginnersandsutable forcloudnetworkservicesduetoitssimplicity、andconcurrencyfeatures.1)installgofromtheofficialwebsiteandverify with'goversion'.2)

並行性パターン:開発者のベストプラクティス並行性パターン:開発者のベストプラクティスApr 26, 2025 am 12:20 AM

開発者は、次のベストプラクティスに従う必要があります。1。ゴルチンを慎重に管理して、リソースの漏れを防ぎます。 2。同期にチャネルを使用しますが、過剰使用を避けます。 3。同時プログラムのエラーを明示的に処理します。 4. GomaxProcsを理解して、パフォーマンスを最適化します。これらのプラクティスは、リソースの効果的な管理、適切な同期の実装、適切なエラー処理、パフォーマンスの最適化を確保し、それによりソフトウェアの効率と保守性を向上させるため、効率的で堅牢なソフトウェア開発には重要です。

生産に進む:現実世界のユースケースと例生産に進む:現実世界のユースケースと例Apr 26, 2025 am 12:18 AM

goexcelsinproductionduetoitsperformanceandsimplicity、butrequirescarefulmanagement of sscalability、errorhandling、andresources.1)dockerusesgofores goforesesgorusesgolusesgotainermanagement.2)uberscalesmicroserviceswithgo、facingchallengesinservicememameme

GOのカスタムエラータイプ:詳細なエラー情報を提供しますGOのカスタムエラータイプ:詳細なエラー情報を提供しますApr 26, 2025 am 12:09 AM

標準のエラーインターフェイスが限られた情報を提供し、カスタムタイプがコンテキストと構造化された情報を追加できるため、エラータイプをカスタマイズする必要があります。 1)カスタムエラータイプには、エラーコード、場所、コンテキストデータなどを含めることができます。2)デバッグ効率とユーザーエクスペリエンスを改善する3)ただし、その複雑さとメンテナンスコストに注意する必要があります。

GOプログラミング言語を備えたスケーラブルなシステムを構築しますGOプログラミング言語を備えたスケーラブルなシステムを構築しますApr 25, 2025 am 12:19 AM

goisidealforbuildingscalablessystemsduetoitssimplicity、効率性、およびビルド・インコンカレンシsupport.1)

GOでINIT機能を効果的に使用するためのベストプラクティスGOでINIT機能を効果的に使用するためのベストプラクティスApr 25, 2025 am 12:18 AM

intionSingOrunautomaticallyは()andareuseforstingupenments andinitializingvariables.usemforsimpletasks、回避効果を回避し、測定可能性を測定することを検討します。

GOパッケージのINIT機能の実行順序GOパッケージのINIT機能の実行順序Apr 25, 2025 am 12:14 AM

goinitializeSpackages intheordertheyareimport extionsitions withinitionsiteintheirdefinition ordord、およびfilenamesdetermineTheOordCrossMultiplefiles.thisprocesccanbeandeanded by -dependenciessedieSiesは、このマイレアドカンフレシニティン化の対象となります

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

AtomエディタMac版ダウンロード

AtomエディタMac版ダウンロード

最も人気のあるオープンソースエディター

VSCode Windows 64 ビットのダウンロード

VSCode Windows 64 ビットのダウンロード

Microsoft によって発売された無料で強力な IDE エディター

SublimeText3 Linux 新バージョン

SublimeText3 Linux 新バージョン

SublimeText3 Linux 最新バージョン

DVWA

DVWA

Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、