Swift的类型推断会不会造成类型不确定的困扰?
标签(空格分隔): Swift 强类型 类型推断
前言
相信看过《The Swift Programming Language》的人对这门语言会有初步的印象:强类型。此外一个经常提到的特点就是类型推断。
强类型的意思就是一个变量或者常量要有确定的类型。类型推断的意思是编译器可以根据赋值的情况(可能还有其他线索)推断出变量或者常量的类型,表面上和某些弱类型语言的写法类似:
// 变量intValue没有显式声明一个特定的类型,编译器会根据其赋值语句推断出它的类型为Int var intValue=10;
我们知道,如果是js这样写没有问题,语法就允许。换做ActionScript(AS3),这样写编译不会报错,但是会给出警告,提示你intValue没有指定类型。那么,Swift中这样写会怎么样呢?答案是可以编译,而且没有警告。在《The Swift Programming Language》中存在大量这样的写法,给人的感觉是在提倡这样写。那么号称强类型的语言怎么这点上和js如此类似呢?这种不确定的类型,会不会给团队协作造成困扰?调用他人的程序,如果对方这样声明属性还能不能获得属性的类型了?本文就要说明这个问题。
猜测
最近在看斯坦福大学的iOS开发视频,里面有一个细节:在类中定义了不是Optional的属性1,如果没有给出初始值,同时没有构造方法或者构造方法中也没有赋值初始化属性,是无法通过编译的,也就是说如果不是可以为nil的属性,必须要给出初始值。这点写过AS3程序的人会特别在意,因为AS3的基本类型都是有一个默认值的,所以即便没有给基本类型的属性赋值,也是允许的。这是两种语言对于属性初始值检查的差异。这个细节也说明既不声明类型也不给初始值,是无法通过初始化检查的。据此我猜测Swift编译器对类型的检查绝对要比AS3严格,前言中Swift的两个特点看似矛盾,其实是假象。
证实
为了验证猜测,在XCode中动手试试就好了。
我会在一个类A中通过类型推测的方式定义属性,在类之外对这个属性进行访问,观察能否得到具体的类型。
声明一个类:
public class ClassA { var intValue=10; var doubleVlaue=10.0 var strValue:String{ get{ return "\(intValue)" } set{ intValue=0 } } }
ClassA具有两个存储属性和一个计算属性,两个存储属性都依赖类型推断声明。经过尝试,计算属性的类型不可省略,省略后无法通过编译。
在另外一个类中实例化ClassA,访问实例的属性:
let s:ClassA=ClassA(); @IBAction func accessTest(sender: UIButton) { s.intValue=1; s.doubleVlaue=23; }
以上代码可以通过编译。以下的尝试不会通过编译:
s.intValue=0.1; s.doubleVlaue="dfdsf";
在编辑器中,鼠标经过类型“模糊”的属性时按下“option”键,鼠标指针变为问号,点击以下鼠标左键,弹出的提示信息中会明确显示属性的类型。上面不能编译通过的赋值语句都是类型不符合造成的。
以上得到的结论就是:通过类型推断获得的类型,并不是在声明范围内的权宜之计,而是持久的改变,就像你自己补全了声明一样。
Swift作为一门强类型语言,声明一个常量或者变量,类型是不可缺少的。类型推断只是一颗语法糖,让程序员偷懒,但不要真的以为这样声明的内容没有一个确定的类型。