为什么Go语言没有计算整数绝对值的函数?

29
在Go中,为什么没有直接计算整数数据类型绝对值的函数?目前,所有整数值都必须转换为float64,然后传递给math.Abs()函数,该函数返回一个float64数字,然后再将其转换回整数。这段代码会引起错误“./prog.go:12:39: cannot use x (type int64) as type float64 in argument to math.Abs”,因为Go是一种静态类型语言,所以它不允许使用不同的数据类型。
package main

import (
    "fmt"
    "math"
)

func main() {
    fmt.Println("Hello, playground")
    var x int64 = -10
    
    fmt.Println("Abolute value ", math.Abs(x))  
}

6
将整数转换为浮点数以使用“math”包,然后再转回整数几乎永远不是正确的做法。大多数简单的“math”函数仅存在于“float64”中的唯一原因是浮点数通常具有许多棘手的边界情况(例如涉及NaN和无穷大),这些情况很难正确处理;整数没有这些问题。 - Dave C
4个回答

22

来自Go的FAQ,

标准库的目的是支持运行时,连接操作系统,并提供许多Go程序所需的关键功能,例如格式化I/O和网络。它还包含了对Web编程非常重要的元素,包括加密和对HTTP、JSON和XML等标准的支持。

没有明确的标准来定义包含什么,因为很长一段时间里,这是唯一的Go库。然而,现在有一些定义新添加内容的标准。

标准库的新添加很少,包含的代码需要承担大量的持续维护成本(通常由原作者以外的人承担),受到Go 1兼容性承诺的约束(阻止API中任何缺陷的修复),并受到Go发布计划的限制,从而防止用户快速获得错误修复。

大多数新代码应该存在于标准库之外,并通过go工具的go get命令进行访问。这样的代码可以有自己的维护者、发布周期和兼容性保证。用户可以在godoc.org上找到包并阅读其文档。

作为对于如何轻松创建整数版本的 math 包浮点函数的回应,Go 团队成员 Russ Cox 曾经开玩笑说道

Ceil、Floor 和 Trunc 更加容易!

一个合理的解释是,由于这个函数很容易编写(如果 x < 0,则 x = -x),它不符合包含的标准。与浮点版本进行比较:
func Abs(x float64) float64 {
    return Float64frombits(Float64bits(x) &^ (1 << 63))
}

这个功能虽然有用但不太明显,这是将其包含在标准库中的一个令人信服的理由。


10
函数实现是否“简单”(对于某人而言)可能不是一个好的衡量标准。更好的衡量标准应该是看人们出错的几率。鉴于我看到的对这个问题的有问题回答以及人们撰写的试图回答这个问题的博客文章,我认为它值得被纳入标准库,因为人们很可能会做错。 - borud
5
同意@borud的观点 - 构建编程语言+相应的标准库的目的不仅仅是“提供复杂的功能” - 为什么要让每个使用标准库的用户都重新编写相同的函数呢? - Tim

10

绝对值是绝对差的一种特殊情况[1],这里将提供整数的绝对值函数和绝对差函数,以及无符号整数的绝对差函数(奖励内容):

package math

func absInt(x int) int {
   return absDiffInt(x, 0)
}

func absDiffInt(x, y int) int {
   if x < y {
      return y - x
   }
   return x - y
}

func absDiffUint(x, y uint) uint {
   if x < y {
      return y - x
   }
   return x - y
}
  1. https://wikipedia.org/wiki/Absolute_difference

这绝对不是回答问题的方式,为什么它没有被包含在标准库中,而不是如何实现它。 - xdavidliu

1

虽然没有标准函数,但你可以自己编写或使用第三方解决方案。这个包包含所有内置有符号整数类型的Abs函数。使用方法(在go get之后):

import (
    "fmt"
    "github.com/adam-lavrik/go-imath/i64" // Functions for i64 type
)
...
x := int64(-2)
fmt.Println(i64.Abs(x)) // Output: 2
x = i64.Minimal // Minimal negative value of int64, has no positive pair
fmt.Println(i64.Absu(x)) // Output: 9223372036854775808 (result is converted to uint64)

1
使用泛型,这个问题变得非常简单。只需为每种整数类型编写一次即可。
import "golang.org/x/exp/constraints"

func Abs[T constraints.Integer](x T) T {
    if x < 0 {
        return -x
    }
    return x
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接