14

我试图了解big int api背后的设计决策。

例如,要添加两个大整数,您必须:

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,这将是一种浪费。计算的整数不仅仅是一个简单的一两个词结构,它可以很大。因此,最好允许使用预定义的 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

我想补充一下 Denys 的回答,如果您考虑替代 api,它可以支持如下链接:

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 回答