存储安全:确保变量先定义再使用
2015-06-12 09:10
381 查看
本文来自南栀倾寒(简书)的投稿,翻译自苹果Swift博客,原文:Memory Safety: Ensuring Values are Defined Before Use
欢迎通过“投稿爆料”渠道或者support@cocoachina.com投稿
我们在用swift设计开发时的一个重点就是如何提高编码模型的内存安全问题。内存安全涉及到很多个方面,所以这篇文章会从一些基础的内容开始,并包含一个简单用例:如何确保变量有一个初始值才能使用。
swift版方法变量什么时候是安全的?开发者认为应该是无论任何时候访问一个变量,它都有一个可用的有效值。语言采用不同的方法以确保安全,像其他编程语言,比如C,要求程序员对内存模型的编程技术非常严格,但是这是有风险的,人总会犯错。C++和OC执行了强制性的模式来改善这种可能造成错误的地方 ,而其他语言则采取了一些极端的措施。Swift使用的主要技术是使用高级编译器执行代码数据流分析。编译器会强制变量在被使用之前进行初始化,这一策略被称为Definitive Initialization。比如Java和C#(尤其)都采用了这种技术。Swift对更广泛范围内的变量使用了这种方法的扩展版本。注意:文章末尾包含其他技术的信息,Swift在某种程度上使用了其中的大部分。初始化局部变量Swift在不少上下文环境中使用了Definitive Initialization的规则,不过局部变量使用的是最简单的。Definitive Initialization比隐式默认初始化规则更为灵活(参看下文),因为类型推断允许你这样写:
var myInstance : MyClass // Uninitialized non-nullable class reference if x > 42 { myInstance = MyClass(intValue: 13) } else { myInstance = MyClass(floatValue: 92.3) } // Okay because myInstance is initialized on all paths myInstance.printIt()编译器可提供if语句两端的验证来初始化myInstance,可以保证不会调用那些未初始化的内存。Definitive initialization是一个很强大的方法,但仅在它是可靠和可预测的时候非常有用。当你有更复杂的控制流时它会让你大吃一惊,比如下边:
var myInstance : MyClass if x > 10 { myInstance = MyClass(intValue: 13) } // ... if x > 42 { myInstance.printIt() }这时编译器可能告诉你 “Variable myInstance used before initialized”在调用printIt()。其实就是说变量未初始化,因为编译器不可能做所有预测或者类型推断,这就要求我们不要写这么复杂的逻辑去初始化一个变量。我们可以让编译器去处理个别的用例,不可能处理所有的用例(这么做相当于halting problem),所以我们要保持编译器规则的简单和可预测性。Swift让初始化一个变量变得非常简单。实际上,在普通数据类型如int初始化时可以直接写var x = 0,给变量一个0初始值,而不是声明未初始化变量var x : Int。可能的情况下,Swift支持初始化的外显性。当使用init()调用时,就有很多强大的方法来初始化一个变量。你可以在Swift Programming Language的"Initialization" 一节中阅读更复杂一些的内容。其他技术补充除了definitive initialization,Swift还在语言的重点范围使用了附加方法。你可以在其他语言中使用这些技术,所以我们在这篇文章会说的很简短。每种方法都有不足,所以它们不是Swift使用的主要方法:将安全问题留给程序员:鉴于C语言的流行程度,所以理解simply leaving safety up to the developer的优缺点非常重要。不幸的是,使用未初始化的值在C语言中产生的未定义的行为(undefined behavior),通常会导致运行时问题(explosions)。C语言依赖程序员不犯错误。由于我们的目标是让Swift默认是安全的,所以一般不会使用这个方法。不过,当明确需要的时候,类似UnsafePointer的API允许你明确地选择不安全性。
隐式初始化:有些值可通过编译器的隐式初始化来保证其安全性,比如设置一个“zero value”,类似Objective-C对实例变量做的那样,或者通过运行默认构造器
(initializer)来实现,比如C++中的。我们对此进行了深度探索,但是最终决定不对其进行广泛的使用,原因是:如果有些Protocol没有要求实现init()方法 这样一个变量就可能引用一个未初始化的对象遗留在Cocoa编程中,这种情况在Swift中很常见。
即便是基本类型,比如整数0经常是错误值。这是在Swift中设置初始值如此简单的一个原因。对于维护人员来说,就算不给变量默认值,自己写一个也并不麻烦,而且会提前发现很多错误,使代码更容易维护。
注意:对于可空类型值来说,默认初始化nil是正确的,所以所有Optional和ImplicitlyUnwrappedOptional类型会默认初始化为nil.定义时要求构造器:在定义变量时,程序员通常要提供一个初始值,也就是说var x : Int没有构造器是不合法的。虽然在函数式语言中这是一个常见的方法,不过这是个非常沉重的要求,因为它强制执行了一个非常严格的编程风格,有碍自然模式的表达。
相关文章推荐
- 正则表达式---JS
- Eigen的使用
- Android Studio的设置教程
- 真机调试 限制设备功能
- Java的委托
- ffmpeg 学习笔记
- Redis命令学习—Hash(哈希表)操作
- Android studio 安装中遇到一些问题的解决办法
- 21Hash算法以及暴雪Hash
- 谷歌开发工具Android Studio安装使用图文教程
- Java中的构造函数
- 数字示波器的使用情况
- Webrtc Intro - Native APIs
- 栈溢出崩溃排查(一)
- C#画笔Pen绘制光滑模式曲线的方法
- JSTL function 标签 使用
- 单片机c语言
- Common Scenarios to avoid with DataWarehousing
- Android Studio安装及配置心得
- 【转】C++ 文件结束符