地图、切片或通道类型的类型安全

问题描述

我想知道为什么这段代码在 go 中编译。我预计会出现编译器错误,例如字符串:

package main

import (
    "fmt"
)

type myMap map[string]int
type mySlice []int
type myChan chan int

type myString string

func main() {
    var mm myMap
    var m map[string]int
    m = mm // fine,but expected compiler error

    var ms mySlice
    var s []int
    s = ms // same with slices

    var mc myChan
    var c chan int
    c = mc // or channels

    var mstr myString
    var str string
//  str = mstr // error,as expected
    fmt.Printf("%T %T %T %T %T %T %T %T\n",mm,m,ms,s,mc,c,mstr,str)
}

Playground
为什么我在使用那些特殊的“引用类型”映射、切片和 chan 时不会出现类型不匹配错误

解决方法

在前两种情况下您不会遇到编译时错误,因为语言规范允许这些赋值

Spec: Assignments:

在赋值中,每个值都必须是 assignable 到它被赋值的操作数的类型...

还有Spec: Assignability:

x分配T 类型的 variable(“x 可分配给 T”)如果以下条件之一适用:

  • x 的类型与 T 相同。
  • x 的类型 VT 具有相同的 underlying types 并且至少 VT 之一不是defined 类型。
  • T 是接口类型,x implements T
  • x 是双向通道值,T 是通道类型,x 的类型VT 具有相同的元素类型,并且在VT 中的至少一个不是定义的类型。
  • x 是预先声明的标识符 nilT 是指针、函数、切片、映射、通道或接口类型。
  • x 是类型为 T 的值的无类型 constant representable

强调规则适用于您的前 2 个案例。但是,它不适用于您的最后一种情况,因为 stringmyString 都是已定义的类型。没有任何规则适用于您的最后一种情况。

,

根据语言规范:

x 的类型 V 和 T 具有相同的底层类型,并且 V 或 T 中至少有一个不是定义的类型。

myMap 是一个定义的类型,但 map[string]int 不是,而且由于底层类型是相同的,所以赋值是有效的。

string 是一个定义的类型,所以分配给另一个定义的类型不起作用。您必须明确复制。