英文:
Aliased types in Go only assignable if unnamed?
问题
在下面的代码片段中,最后三个赋值语句会产生编译错误:
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中至少有一个不是命名类型。
- [...]
(Go规范:可赋性)
以及
[...] 命名类型由(可能是限定的)类型名称指定;未命名类型使用类型字面量来指定,它从现有类型组合成一个新类型。[...]
(Go规范:类型)
综合起来,为什么别名的赋值不能工作是因为最后三种情况的类型是命名类型。通过这个规则,违反了两个命名类型参与赋值的规则。
现在是我真正的问题:
为什么不允许将别名的字符串/布尔值/数值赋值给实际的字符串/布尔值/数值,而不是像切片和数组这样的类型?
缺乏这个规则会导致哪些问题?
将字符串指定为命名类型会导致哪些问题?
提前谢谢你的回答。
英文:
In the following code snippet the last three assignments produce a compilation error:
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
)
}
This means that, in this example, only bools, strings and floats are not assignable.
The reason for this can be found in the specification:
> A value x is assignable to a variable of type T ("x is assignable to
T") in any of these cases:
>
> - [...]
> - x's type V and T have identical underlying types and at least one of V or T is not a named type.
> - [...]
(Go Specification: Assignability)
and
> [...] Named types are specified by a (possibly qualified) type name; unnamed types are specified using a type literal, which composes a new type from existing types. [...]
Combining this, the reason why the aliased assign does not work is because the types of the last three cases are named. Through this the rule is violated: Two named types are part of the assignment.
Now to my actual question(s):
Why should it not be allowed to assign an aliased string/bool/numeric to an actual string/bool/numeric, as opposed to types like slices and arrays?
What kinds of problems would the lack of this rule cause?
What kinds of problems would the specification of a string as a named type cause?
Thank you in advance.
答案1
得分: 0
可赋值性规则意味着有时你需要在命名类型之间进行转换,明确地表示“是的,我希望将这个string
作为Foo
使用”,即使它们共享相同的基础类型。这对于像os.FileMode
这样的东西很重要:它在底层是一个数字,但类型检查会防止你意外地将其传递给接受不相关的foo uint32
的函数。(可赋值性规则也会影响函数调用:你可以传递任何可赋值给参数类型的类型的参数。)
一般来说,这意味着如果你对底层类型有不同的、可能混淆的用途,你可以为它们分配不同的名称。比如:底层类型[][4]float32
可以合理地分配RGBASlice
、HSVASlice
和XYZWSlice
类型名称。你不能将RGBASlice
传递给期望XYZWSlice
的函数。但是所有这些都可以透明地传递给不关心数字含义的东西,比如如果你有一些通用的向量数学例程。
因此,总体上,通过强制你在命名类型之间进行转换,Go帮助你区分那些在内存中可能具有相同表示但具有不同含义并且应该在不同位置使用的东西。
英文:
The assignability rules mean you sometimes have to convert between named types to explicitly say "yes, I mean this string
to be used as a Foo
," even if they share the same underlying type. This is relevant to things like os.FileMode
: it's a number underneath, but type checks will keep you from accidentally passing it to a function that takes an unrelated foo uint32
. (Assignability rules affect function calls, too: you can pass an argument of any type that's assignable to the parameter type.)
Generally, this means if you have distinct, potentially confusable uses for an underlying type, you can assign different names to them. Like: the underlying type [][4]float32
could plausibly have RGBASlice
, HSVASlice
, and XYZWSlice
type names assigned. You can't pass a RGBASlice
to a function that expects an XYZWSlice
. But all can be passed transparently to things that don't care about the meanings of the numbers, like if you have some all-purpose vector-math routines.
So, broadly, by forcing you to convert between named types, Go helps you distinguish between things that might have the same representation in memory even though they have different meanings and are supposed to be used different places.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论