【问题标题】:In Go, when should you use uint vs int?在 Go 中,什么时候应该使用 uint 和 int?
【发布时间】:2020-11-16 04:45:17
【问题描述】:

乍一看,当您需要一个不想成为负数的 int 时,似乎有人可能会选择 uint。然而,在实践中,int 似乎总是首选。

我看到如下一般性建议:

  • “通常,如果您使用整数,则应该只使用 int 类型。”
  • “uint 通常只应用于二进制操作”
  • “不要使用无符号类型来强制或建议数字必须为正数。这不是它们的用途。”
  • “这是 Go 编程语言所推荐的,当你想进行按位运算时,uint 的具体示例很有用”

我还注意到 Go 会让你将负整数转换为 uint 并给出一些奇怪的结果:

    x := -5
    y := uint(x)
    fmt.Println(y)

>> 18446744073709551611

所以,我的理解是,在处理整数时,无论符号如何,我都应该始终使用 int,除非我发现自己需要 uint,而且在这种情况下我会知道(我认为???)。

我的问题:

  • 这是正确的外卖吗?
  • 如果是这样,为什么会这样?
  • 什么时候应该使用 uint 的例子是什么? -- 也许是一个具体的例子,而不是“当做二进制操作时”,因为我不确定我知道这意味着什么:)

另外,我问的是 Go 的具体实现。

【问题讨论】:

  • 这真的和 Go 无关。任何同时具有 int 和 uint 类型的语言都有相同的注意事项。
  • @Flimzy:它有特定的部分。 go 更喜欢 int 的一个原因是,当你误用 int 时,你会得到更多有用的恐慌。
  • @Dani 有什么例子可以让你用 int 得到一个有用的恐慌?
  • ints 是数字,uints 是位模式。就是这么简单。
  • 同事:“我们用 uint 表示人的年龄,因为它不能为负数。”我:“一般建议是使用 int,除非你需要 uint。”同事:“为什么?”我:

标签: go


【解决方案1】:

Package Image 使用 uint 和 crypto/tls,所以当你使用这些包时你必须使用 uint。

我一开始是合乎逻辑地使用它,但我不会为此而争吵,如果它成为一个问题,我会使用实用的方法。

点赞why using int for len()

【讨论】:

    【解决方案2】:

    This answer 用于 C,但在这里是相关的。

    通常,如果您使用整数,则应该只使用 int 类型。

    建议通常这样做,因为我们“通常”遇到的大多数代码都处理类型int。您通常也不需要在使用 intuint 类型之间进行选择。

    不要使用无符号类型来强制或建议数字必须为正数。这不是他们的目的。

    这是相当主观的。您可以很好地使用它来保持您的程序和数据类型安全,并且不必为处理由于负整数情况而导致的偶发错误而烦恼。

    “这是 Go 编程语言所推荐的,当你想进行按位运算时,uint 的具体示例很有用”

    这看起来很模糊。请添加此来源,我想阅读它。

    x := -5
    y := uint(x)
    fmt.Println(y)
    
    >> 18446744073709551611
    

    这是许多语言的典型特征。这背后的逻辑是,当您将int 类型转换为uint 时,用于int 的二进制表示会被挤入uint 类型中。最后,一切都只是二进制的抽象。 例如,看看这段代码及其输出:

    a := int64(-123)
    byteSliceRev := *(*[8]byte)(unsafe.Pointer(&a))      // The byte slice representation we get is LTR in increasing order of significance
    u := uint(a)
    byteSliceRevU := *(*[8]byte)(unsafe.Pointer(&u))
    byteSlice, byteSliceU := make([]byte, 8), make([]byte, 8)
    for i := 0; i < 8; i++ {
        byteSlice[i], byteSliceU[i] = byteSliceRev[7-i], byteSliceRevU[7-i]
    }
    fmt.Println(u)
    // 18446744073709551493
    fmt.Printf("%b\n", byteSlice)
    // [11111111 11111111 11111111 11111111 11111111 11111111 11111111 10000101]
    fmt.Printf("%b\n", byteSliceU)
    // [11111111 11111111 11111111 11111111 11111111 11111111 11111111 10000101]
    

    -5int64 类型的字节表示与18446744073709551493uint 类型的字节表示相同。

    所以,我的理解是,在处理整数时,无论符号如何,我都应该始终使用 int,除非我发现自己需要 uint,而且在这种情况下我会知道(我认为???)。

    但对于“我们”编写的每一个代码,这不是或多或少都是真的吗?!

    这是正确的外卖吗? 如果有,为什么会这样?

    我希望我已经回答了这两个问题。如果您仍有任何疑问,请随时问我。

    什么时候应该使用 uint 的例子是什么? -- 也许是一个具体的例子,而不是“当做二进制操作时”,因为我不确定我知道那是什么意思:)

    想象一个场景,您的数据库中有一个表,其中有很多条目,其中一个整数为id,它始终为正数。如果您将此数据存储为int,则每个条目的一位实际上是无用的,并且当您对其进行缩放时,如果您可以使用uint 并保存它,则会丢失大量空间。在传输数据时可以考虑类似的情况,准确地说是传输大量整数。此外,uint 与对应的有符号整数相比,正整数的范围是双倍的,因为有额外的位,因此用完数字需要更长的时间。存储现在很便宜,所以人们通常会忽略这个所谓的小收益。

    另一个用例是类型安全。 uint 永远不会是负数,所以如果你的代码的一部分对负数很敏感,它可以证明是非常方便的。最好在将资源浪费在数据上之前得到错误,只是为了发现它是不允许的,因为它是负面的。

    【讨论】:

    • 谢谢!但我的观察是,惯用的 Go 做事方式是更喜欢 int。从表面上看,如果您不知道一般建议,那么选择限制性更强的 uint 似乎是合乎逻辑的。另外,我想我正在特别考虑在 Go 中进行内存工作。我绝对明白您关于使用 uint 优化大小以进行数据库存储或传输数据的观点。但是在 Go 的内存中,使用 uint 似乎确实很容易,但一般建议是不要这样做。为什么?只是很容易不去想它并使用 int (当 size 和 max # 不是问题时)?
    • 或者我的前提是错误的?在我描述的情况下,更喜欢 int 不是惯用的 Go 吗?在类型安全方面,考虑到将负 int 推入 uint 是多么容易,感觉并不安全。从最严格的意义上讲,也许没有违反类型安全,但感觉不像我期望的那样。也许这是推荐的一个关键原因?
    • 这里有一个参考,提示了我的很多问题:reddit.com/r/golang/comments/8plmo0/…
    • "但我的观察是,惯用的 Go 做事方式是更喜欢 int。从表面上看,如果你不知道一般建议,选择限制性更强的 uint 似乎是合乎逻辑的。 "这很可能是您的观察,但请理解答案“什么是惯用语?”是相当主观的。您会发现人们在if-else 子句中为将牙套放在哪里而争吵不休,理由很充分,但没有人会赢,因为这实际上是主观的。
    • 我们得到的最终结果是一个规则列表,可以让每个人的生活更轻松,而且对于所有规则,人们都会不同意,这没关系。这不是关于我不知道这些建议,这本身就是由真实的人和人们推荐各种各样的东西。这是关于我认为是对的。 uint 在整个 Go 标准库中使用,在像 image 这样的包中很可能是出于我提到的原因。使用 uint 带来的类型安全是 Go 推荐的最惯用的东西之一。只是,imo,int 很简单,更自然。
    猜你喜欢
    • 2011-03-08
    • 2012-07-15
    • 2013-11-13
    • 1970-01-01
    • 2019-04-13
    • 2015-12-05
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    相关资源
    最近更新 更多