为什么我们需要一个类型?
在回答这个问题之前,我们需要看看一些我们现在没有处理的编程语言的原始抽象层。
我们如何才能获得数据的机器表示?
二进制0和1。这是机器所理解的。但这对我们有意义吗?直到你能看到类似这样的东西之后,才对我有用。
因此,我们可以抽象出这些二进制0和1并在梯形图中向上移动一步。
考虑这个程序集片段。
你能说出寄存器R1,R2,R3中的数据类型是什么吗?
你可能希望它们是整数,因为在汇编语言级别无法确定它们。没有任何东西阻止R1,R2和R3具有任意类型,因为它们只是一堆0和1的寄存器,并且添加操作将很乐意接受它们并将它们加起来即使它没有意义,然后产生一个位模式,然后存储到R1中。
因此,这种类型的概念从更高级的抽象开始,在更高级别的语言中,如C,Go,Java,Python,JavaScript等,并且是语言本身的特征。
某些语言在运行时执行此类型检查,而有些语言在编译时执行它。
什么是类型?
类型的概念确实从编程语言到编程语言不同,并且可以用许多不同的方式表达,但大致它们都有某种共识。
类型是一组值。对这些值的一组操作,例如,我们可以添加(+),减去(-)等的整数类型,而我们可以连接的字符串类型,执行空检查等。因此,语言类型系统指定哪些操作对哪些类型有效。
类型检查的目标是确保仅使用正确类型的操作。通过这种类型检查强制执行预期的值解释,因为没有其他任何东西可以检查,因为一旦我们得到机器级代码,它只是很多0和1,并且机器将很乐意做我们告诉的任何操作在那些0和1上。
TypeSystem用于强制执行这些位模式的预期解释,并确保整数的位模式不对其执行任何非整数运算,并获得无意义的内容。
Go中的类型系统
有一些基本规范可以控制GoSystem中的TypeSystem。我们将看一些重要的一个。
但是,不要只是立刻放下所有的概念,在这里我将尝试使用不同的例子来涵盖GoTypeSystem的一些基本概念,然后在解释一些基本概念时将引导你完成这些示例。
请稍等一下,看看这些代码片段。其中哪一个会编译,为什么或为什么不编译?
我希望你记下你的答案和原因,所以最后你和我在一起我们可以推理这个。
名称(已定义)类型
具有名称的类型:例如int,int64,float32,string,bool等。这些是预先声明的。
我们使用类型声明创建的任何类型也都被命名为typed。
未命名的类型
复合类型-数组,结构,指针,函数,接口,切片,映射和通道类型均为未命名类型。
因为他们没有名字,但有关于如何构建的类型字面描述。
基础类型
每种类型T都有底层类型。
所以行号
3&8我们有预先声明的字符串类型,因此底层类型将是T本身,即字符串
5&7我们有一个类型文字,因此底层类型将是T本身,即map[string]int和*N指针。*注意这些类型的文字也是未命名的类型
4,6和10T的基础类型是T在其类型声明中引用的类型的基础类型。B指的是A因此字符串等等。
需要再次查看的案例是第9行。
输入Tmap[S]int。由于S底层类型是字符串。Tmap[S]int的基础类型不应该是map[string]int而不是map[S]int,因为这里我们讨论的是底层未命名类型map[S]int和底层类型在第一个未命名类型时停止(或者如规范所说“如果T是类型文字,则相应的基础类型是T本身”)。
你可能在思考为什么我对这些未命名类型,命名(已定义)类型和基础类型的规范施加了太多压力,因为它在我们将要进一步讨论的规范中起重要作用,以帮助我们理解为什么代码上面发布的片段将编译或甚至不会在意图大部分相同时编译。
可转让性
当变量v可以分配给变量以键入T.
虽然条件是自我解释的,但让我们看看规范中的规则之一,在分配时,
两者都应具有相同的基础类型,并且其中至少有一个不是命名类型。
让我们再看一下图4和图5的片段问题
所以上面的代码不会编译,会给我们编译时错误。
因为i是命名类型int而ai是命名类型aInt,即使它们的底层类型相同。
snippet4将编译,因为m是未命名的类型,m和mMap的基础类型相同。
类型转换
上面的代码将编译,因为Meter和Centimeter都是整数类型,它们的底层类型可以在彼此之间转换。
在我们研究图1和图2中的代码之前。让我们看一下在Go中管理类型系统的另一个基本规范。
类型识别
两种类型相同或不同。
定义的类型总是与任何其他类型不同。否则,如果它们的基础类型文字在结构上相同,则两种类型是相同的。
所以即使是预先声明的命名(已定义)类型int,int64等也不相同。
然后查看struct的转换规则,
忽略struct标签,x的类型和T具有相同的底层类型。
请注意术语“相同的基础类型”。由于字段Meter.value的基础类型是int64而字段Centimeter.value是int32,因此它们不相同,因为定义的类型总是与任何其他类型不同。
因此,我们将从图2中获取代码段代码的编译错误,而在图1的代码段中
字段Meter.value的基础类型为int64,字段Centimeter.value为int64。所以它们完全相同。因此转换没有任何编译错误。