14

私はbigintapiの背後にある設計上の決定を理解しようとしています。

たとえば、2つの大きなintを追加するには、次のことを行う必要があります。

a := big.NewInt(10)
b := big.NewInt(20)
c := big.NewInt(0)
d := c.Add(a,b)

ここで、dは最後のcと同じです。最初のゼロは少し重要ではありません。

なぜだけではないのですか?

a := big.NewInt(10)
b := big.NewInt(20)
c := big.Add(a,b)

またはさらに良い:

a := big.NewInt(10)
b := big.NewInt(20)
c := a.Add(b)

彼らがこのようにすることを選んだ理由はありますか?少し混乱しているので、使用するたびに調べなければなりません。

4

2 に答える 2

11

Addレシーバーを変更する方法です。

だからただする

c := big.NewInt(0).Add(a,b)

また

var c big.Int
c.Add(a,b) 

Add がレシーバーを返すという事実は、関数チェーンに役立ちますが、戻り値を使用する必要はありません。

ここで、レシーバーとして bigInt がない場合 ( c := big.Add(a,b))、またはレシーバーが変更されない場合 ( c := a.Add(b)) を考えてみましょう。どちらの場合も、操作のためだけに大きな Int を割り当てて (ポインターとして) 返す必要があります。大きな Int が割り当てられて準備ができている場合、これは無駄になります。計算される整数は、単純な 1 語または 2 語の構造体ではなく、大きくなる可能性があります。したがって、特に計算ループの途中で大きな整数を使用することが多いため、事前定義された var の使用を許可することをお勧めします。

c := big.Add(a,b) // wasteful because doesn't allow the use of a preexisting big int

c := a.Add(b) // either modifies a (which would force you to copy it each time if you want to keep it) or is wasteful like the last one
于 2012-11-22T13:51:20.697 に答える
3

次のようにチェーンをサポートできる代替APIを検討する場合、Denysの回答に追加します。

x.Add(y).Add(z).Mul(v) 

すぐに質問があります-これは通常のオペレーターの順序に従いますか?

x+y+z*v = x+y+(z*v) 

ただし、最初のチェーンは (x+y+z)*v になります (go では、おそらく別の言語ではそうではありません) - したがって、注意が必要です。

これ:

r = r.AddP(x, y.Add(y, z.Mul(z, v)))

やや醜いです、私は同意しますが、明示的な順序を強制し、追加の割り当てなしでオペランドを変更しないままにする機会も与えます(Denysが述べたように)。例(rは毎回レシーバーであることに注意してください):

r = r.Add(x, r.Add(y, r.MulInt(z, v)))

ここでは、結果の値 (r) のみが変更され、x、y、z は変更されません。最初のスタイル API でこれを行うには、毎回割り当てが必要です。その場合、big.Int API でオペランドを変更するか、割り当てるかのいずれかのオプションがあります。

ところで、以下は最初の連鎖と同等です...

r = r.Mul(r.AddP(x, r.Add(y, z)), v) 

実際には (x+y+z)*v のようにもう少し明示的に見えます

于 2015-08-06T10:07:32.580 に答える