为什么Go中的大型int api如此奇怪?

时间:2012-11-22 13:46:54

标签: go biginteger

我正在尝试理解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)

他们选择这样做有什么理由吗?我发现它有点混乱,每当我使用它时都要查找它。

2 个答案:

答案 0 :(得分: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并准备就绪,这将是浪费。计算的整数不仅仅是一个简单的一个或两个单词struct,它可能很大。所以最好允许使用预定义的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

答案 1 :(得分:2)

我想补充一下丹尼斯的答案,如果你考虑替代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