【问题标题】:Why does %T not print the type of my constant?为什么 %T 不打印我的常量的类型?
【发布时间】:2018-11-29 04:18:29
【问题描述】:

我只是在使用官方教程/教程学习 golang。在其中一个示例中,我看到一条注释为An untyped constant takes the type needed by its context.

我正在尝试这个:

package main

import "fmt"

const (
    // Create a huge number by shifting a 1 bit left 100 places.
    // In other words, the binary number that is 1 followed by 100 zeroes.
    Big = 1 << 100
)

func main() {
    fmt.Printf("Big is of type %T\n", Big)
}

但是当我运行它时失败了:

# command-line-arguments
./compile63.go:12:13: constant 1267650600228229401496703205376 overflows int

为什么我无法以这种方式发现常量的类型? (请注意,我完全是个菜鸟,很可能还没有发现足够的语言来自己解决这个问题)。

【问题讨论】:

  • Go 非常擅长在运行代码之前捕获错误,这就是这里发生的事情。在你修复它之前,它不会编译
  • @Derek:int64 类型无法容纳这么大的数字。
  • 哎呀,我没有看到其余的号码(在移动设备上)
  • 查看相关/可能重复的How does Go perform arithmetic on constants?
  • @icza:这与算术无关。这是关于分配期间的默认类型。

标签: go types constants


【解决方案1】:

func Printf

func Printf(format string, a ...interface{}) (n int, err error)

Printf 根据格式说明符格式化并写入标准 输出。它返回写入的字节数和任何写入错误 遇到过。


The Go Programming Language Specification


Variable declarations

变量声明创建一个或多个变量,绑定 给它们对应的标识符,并给它们一个类型和一个 初始值。

如果给出了表达式列表,则变量被初始化为 遵循分配规则的表达式。否则,每个 变量被初始化为零值。

如果存在类型,则为每个变量指定该类型。否则, 每个变量都被赋予了相应的初始化类型 赋值中的值。如果该值是无类型常量,则它是 首先转换为其默认类型;如果它是一个无类型的布尔值 值,它首先被转换为布尔类型。预先声明的值 nil 不能用于初始化没有显式类型的变量。


Constants

常量可以有类型也可以无类型。字面常量,真,假, iota,以及某些仅包含无类型的常量表达式 常量操作数是无类型的。

一个常量可以通过常量声明显式地赋予一个类型,或者 转换,或在变量声明或变量中使用时隐式转换 赋值或作为表达式中的操作数。如果 常量值不能表示为相应的值 输入。

一个无类型的常量有一个默认类型,它是 常量在有类型值的上下文中被隐式转换 例如,在 i := 0 这样的短变量声明中是必需的 没有显式类型的地方。无类型的默认类型 常量是 bool、rune、int、float64、complex128 或 string 分别取决于它是布尔值、符文、整数、 浮点数、复数或字符串常量。


Numeric types

数字类型表示整数或浮点值的集合。 一些预先声明的独立于架构的数字类型:

int32       the set of all signed 32-bit integers (-2147483648 to 2147483647)
int64       the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807)

n 位整数的值是 n 位宽,用 二进制补码算法。

还有一些预先声明的数字类型 实现特定的大小:

uint     either 32 or 64 bits
int      same size as uint

Big 是一个无类型常量。没有可发现的类型。在变量或赋值中使用时,它会被赋予一个类型。无类型常量Big 的默认类型是int

const Big = 1 << 100

在 Go 中,所有参数都按值传递,就像通过赋值一样。对于fmt.Printf,第二个参数是interface{} 类型。因此,等价地,

var arg2 interface{} = Big  // constant 1267650600228229401496703205376 overflows int
fmt.Printf("Big is of type %T\n", arg2)

无类型整数常量的默认类型是int。溢出是编译时错误。


例如,

package main

import "fmt"

const (
    // Create a huge number by shifting a 1 bit left 100 places.
    // In other words, the binary number that is 1 followed by 100 zeroes.
    Big = 1 << 100
)

func main() {
    var arg2 interface{} = Big
    fmt.Printf("Big is of type %T\n", arg2)

    fmt.Printf("Big is of type %T\n", Big)
}

游乐场:https://play.golang.org/p/9tynPTek3wN

输出:

prog.go:12:6: constant 1267650600228229401496703205376 overflows int
prog.go:15:13: constant 1267650600228229401496703205376 overflows int

参考:The Go Blog: Constants

【讨论】:

  • 感谢您提供参考!
【解决方案2】:

虽然无类型常量确实采用其上下文所需的类型,但它可以假定的类型受到语言原语的限制,因此这么大的常量实际上无法在代码中的任何地方使用,因为事实上它甚至不适合 uint64。它的唯一用途是在另一个常量表达式中使用它,否则总是会抛出该错误。

请注意,在Printf(和类似函数)中,常量被转换为interface{},因此默认情况下它采用int 类型。对于 32 位机器,如果您有一个溢出 int32 的常量表达式,则需要先进行类型转换。

const i = 1 << 50
fmt.Println(i) // => constant 1125899906842624 overflows int
fmt.Println(int64(i)) // => 1125899906842624

如果您想对任意大的数字进行适当的算术运算,有一个方便的软件包:math/big

i := big.NewInt(1)
i.Lsh(i, 100)
fmt.Println(i.String())

Playground

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-06-13
    • 2013-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多