Why does standard golang big.Int function use the receiver if it takes two arguments and returns a value?

huangapple go评论73阅读模式
英文:

Why does standard golang big.Int function use the receiver if it takes two arguments and returns a value?

问题

函数:

// Mod将z设置为模数x%y(y!= 0)并返回z。
// 如果y == 0,则会发生除以零的运行时恐慌。
// Mod实现欧几里德模数(与Go不同);有关更多详细信息,请参见DivMod。
func(z * Int)Mod(x,y * Int)* Int {

如果我想在条件中使用一个函数,我需要创建一个临时变量来避免被覆盖:

var tmp big.Int
for tmp.Mod(x,y).Cmp(z)== 0 {
  1. 这样做有什么实际好处吗?
  2. 我能否在不使用临时变量的情况下重写我的代码?
英文:

The function:

// Mod sets z to the modulus x%y for y != 0 and returns z.
// If y == 0, a division-by-zero run-time panic occurs.
// Mod implements Euclidean modulus (unlike Go); see DivMod for more details.
func (z *Int) Mod(x, y *Int) *Int {

If I want to use a function in conditions, I need to create a temporary variable to avoid being overwritten:

var tmp big.Int
for tmp.Mod(x, y).Cmp(z) == 0 {
  1. Is there any practical benefit from this?
  2. Can I rewrite my code without using a temporary variable?

答案1

得分: 4

通常,接收器用于存储结果,因此您可以选择重用现有的big.Int实例。如果您不想重用现有实例,可以为结果创建一个新实例,并在该实例上调用方法。

这在math/big包的文档中有提到:

> 通过始终通过接收器传递结果值,可以更好地控制内存使用。操作可以重用为结果值分配的空间,将该值覆盖为新的结果。

结果也会被返回,以便您可以链接调用。这也在包文档中有提到:

> 例如,(*Int).Add的参数被命名为x和y,因为接收器指定了结果的目标,所以它被称为z:
>
> func (z *Int) Add(x, y *Int) *Int
>
> 这种形式的方法通常也会返回传入的接收器,以便实现简单的调用链。

因此,您可以这样做:

one := big.NewInt(1)
two := big.NewInt(2)
three := big.NewInt(3)

sum := new(big.Int)
sum.Add(sum, one).Add(sum, two).Add(sum, three)
fmt.Println(sum)

这将输出(在Go Playground上尝试):

6

如果您不想重用现有值作为操作的结果,可以像这样分配一个新值:

one := big.NewInt(1)
two := big.NewInt(2)

fmt.Println(new(big.Int).Add(one, two))

这将打印出3(在Go Playground上尝试)。

英文:

Typically the receiver is used for the result so you have the option to reuse an existing big.Int instance. If you don't want to reuse an existing one, you may create a new one for the result and call the method on that.

This is mentioned in the package doc of math/big:

> By always passing in a result value via the receiver, memory use can be much better controlled. Instead of having to allocate new memory for each result, an operation can reuse the space allocated for the result value, and overwrite that value with the new result in the process.

The result is also returned so you can chain invocations. This is also mentioned in the package doc:

> For instance, the arguments for (*Int).Add are named x and y, and because the receiver specifies the result destination, it is called z:
>
> func (z *Int) Add(x, y *Int) *Int
>
> Methods of this form typically return the incoming receiver as well, to enable simple call chaining.

So you may do something like this:

one := big.NewInt(1)
two := big.NewInt(2)
three := big.NewInt(3)

sum := new(big.Int)
sum.Add(sum, one).Add(sum, two).Add(sum, three)
fmt.Println(sum)

Which will output (try it on the Go Playground):

6

If you don't want to reuse an existing value for the result of an operation, you may allocate a new like this:

one := big.NewInt(1)
two := big.NewInt(2)

fmt.Println(new(big.Int).Add(one, two))

Which prints 3 (try it on the Go Playground).

huangapple
  • 本文由 发表于 2021年11月5日 16:59:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/69850718.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定