Types Go中的别名类型仅在未命名时可分配?
在以下代码段中,最后三个赋值产生编译错误:Types Go中的别名类型仅在未命名时可分配?,types,go,assign,Types,Go,Assign,在以下代码段中,最后三个赋值产生编译错误: package main type ( Foo []float64 Baz [2]float64 Meh map[string]string Faq chan int Tet func() Hue interface{} Tai bool Foz string Bar float64 ) func main() { var ( foo Foo = []
package main
type (
Foo []float64
Baz [2]float64
Meh map[string]string
Faq chan int
Tet func()
Hue interface{}
Tai bool
Foz string
Bar float64
)
func main() {
var (
foo Foo = []float64{1, 2, 3}
_ []float64 = foo
baz Baz = [...]float64{1, 2}
_ [2]float64 = baz
meh Meh = make(map[string]string)
_ map[string]string = meh
faq Faq = make(chan int)
_ chan int = faq
tet Tet = func() { return }
_ func() = tet
hue Hue = "Hello, World"
_ interface{} = hue
tai Tai = true
_ bool = tai // error
foz Foz = "Hello, World"
_ string = foz // error
bar Bar = 1
_ float64 = bar // error
)
}
这意味着,在本例中,只有布尔、字符串和浮点是不可赋值的。
其原因可在规范中找到:
值x可分配给类型为T的变量(“x可分配给
T”)在任何此类情况下:
- [……]
- x的类型V和T具有相同的底层类型,并且V或T中至少有一个不是命名类型
- [……]
提前感谢。可分配性规则意味着您有时必须在命名类型之间进行转换,以明确表示“是的,我的意思是此
字符串
用作Foo
”,即使它们共享相同的基础类型。这与os.FileMode
:下面是一个数字,但类型检查会防止您意外地将其传递给一个接受不相关foo uint32
的函数。(可分配性规则也会影响函数调用:您可以传递可分配给参数类型的任何类型的参数。)
通常,这意味着,如果您对底层类型有不同的、可能容易混淆的用法,则可以为它们指定不同的名称。例如:底层类型[[4]float32
可能会分配RGBASlice
、HSVASlice
、和XYZWSlice
类型名称。不能将RGBASlice
传递给需要XYZWSlice
的函数。但所有这些都可以透明地传递给那些不关心数字含义的东西,比如如果你有一些通用的向量数学例程
因此,广义上讲,通过强制您在命名类型之间进行转换,Go可以帮助您区分内存中可能具有相同表示形式的事物,即使它们具有不同的含义并且应该在不同的位置使用。您当然可以问“为什么我不能使用不同的语言?”有关堆栈溢出的问题,答案可能是“看起来你可以,现在你只需要实际建造它。”不过,我更喜欢回答帮助人们建造东西的问题,而不是学术问题。@Two好吧,我问这个问题的主要原因是因为我知道Go的设计师花了很多心思,因此,这项决定背后大概有某种想法,我看不到。很抱歉,这个问题不是为了解决一个特定的问题,而是一个关于语言设计的问题(一般来说,因为我认为围棋并不是唯一一种执行这一规则的语言)。我在这里问的是希望比我更了解语言设计的人能够解释为什么事情通常是这样做的。我认为有一种方法可以将此作为一个编程问题来解决(“我如何使用两个命名类型的不可赋值性?”),我给你一个机会。如果你真的喜欢用花哨的类型技巧做什么,那就看看ML或Rust之类的语言。Go试图让事情比较基本。首先,谢谢。第二,这本质上是否意味着Go声明为命名类型的类型在实践中更容易被其他类型混淆别名?您的答案使严格的可赋值性看起来像是命名类型的一个优势(“[…]但类型检查将防止您意外地将其传递给一个使用不相关的foo uint32”的函数),但同时,反转参数像是未命名类型的一个优势(“但是,所有这些都可以透明地传递给那些不关心数字含义的东西[…]”。嗯,我认为这里的一种思考方式是,您命名一个类型,以声明在组件之外还有一些特殊含义。
[…]float32
是float32数组的任何一个片段,没有额外的意义,因此它很乐意使用RGBASlice
RGBASlice
和XYZWSlice
确实有不同的意义,如果你想把一个作为另一个传递,你需要转换来告诉编译器它是有意的r我认为,如果使用一种未命名的赋值需要显式转换的语言,那就太疯狂了。这只是我考虑何时使用[]4]的一种方式float32
与RGBASlice
相比,如果我编写的代码同时处理这两个问题。编译器仍然将uint32
和FileMode
视为不可赋值,但不是[[4]float32
和RGBASlice
——这在实践中是可行的,但没有关于为什么这个结果天生正确的伟大理论。