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中至少有一个不是命名类型
  • [……]
()

[…]命名类型由(可能是限定的)类型名指定;未命名的类型是使用类型文本指定的,该文本从现有类型组成一个新类型。[……]

()

综上所述,别名分配不起作用的原因是最后三种情况的类型都已命名。这样就违反了规则:两个命名类型是赋值的一部分

现在谈谈我的实际问题:

为什么不允许将别名字符串/bool/numeric分配给实际字符串/bool/numeric,而不是像片和数组这样的类型

缺少这条规则会导致什么样的问题

将字符串指定为命名类型会导致什么类型的问题


提前感谢。

可分配性规则意味着您有时必须在命名类型之间进行转换,以明确表示“是的,我的意思是此
字符串
用作
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
——这在实践中是可行的,但没有关于为什么这个结果天生正确的伟大理论。