再议Swift操作符重载
今天我们来谈一谈Swift中的操作 符重载,这一功能非常实用,但是也相当有风险。正所谓“能力越大责任越大”,这句话用来形容操作符重载最合适不过了。它可以令你的代码更加简洁,也可以让 一个函数调用变得又臭又长。而对于那些没怎么读过你的代码的人来说,操作符的使用同时也会让代码的可读性大打折扣。
谨
慎引入,按需使用。比如在连接两个字串的时候你就可以通过重载加法来实现。甚至于你仅在屏幕上输入一个加号,就能响应一个网络链接、播放一段音乐或者完成
你能实现的其他任何功能。然而过于复杂的功能对编码来说简直就是灾难,合理的做法就是仅在必要时重载操作符,不做任何多余的事。如果你非要做点奇怪的事,
那就为网络响应这样的功能取一个明显又合适的函数名。
无论你何时想采用运算符重载,你都需要考虑一下是否值得重载它而不是用一个函数调用。函数调用或许颇费周折,但更能确切的表达它的功能(如果函数名恰到好处的话)。假如你要频繁做类似于加减乘除赋值比较的操作,那么运算符重载的确是个很合适的解决方案。
运算符重载
在Swift里面你应该就像平时使用运算符那样来使用重载算符。虽然仍然有些不足的地方,不过下面的这个例子足够说明重载运算符的使用了。这段代码计算的是两个NSDate对象间的差值,使用了“laterDate–initialDate” 的形式:
func - (left: NSDate, right: NSDate) -> NSDateComponents
{
let mostUnits: NSCalendarUnit = .YearCalendarUnit | .MonthCalendarUnit | .DayCalendarUnit | .HourCalendarUnit | .MinuteCalendarUnit | .SecondCalendarUnit
let components = NSCalendar.currentCalendar().components(mostUnits, fromDate: right, toDate: left, options:nil)
return components
}
在这个函数中,第一行看上去很多,然而mostUnits表示的不过是我们所关心的日期单元(NSCalendarUnit)的清 单,在这里我选择关注的是年、月、日、时、分、秒。值得注意的是这里并非只有这些日期单元的Flag,可选的还有很多,如果我想知道两个日期之间相隔的周 数我一样可以用别的Flag来替换掉上面这些,使用这些不同Flag可以满足我们对日期计算的大部分需求。往下的一行中,使用了当前时间 NSCalendar.currentCalendar()的components()方法创建了一个NSDateComponents对象,之后在方法 最后返回了这个对象components.
在两个值之间的运算成为中缀运算,运算重载还有后缀运算和前缀运算两种。比如++i和i++分别就是前缀和后缀运算。
如你所见,Swift中所谓重载不过是挂羊头卖狗肉,实际上也只是一个函数调用而已,只不过函数名变成了符号。我们指定了表达式中左右参数的类型,并且还指定了计算结果返回的数据类型必须是一个NSDateComponents对象,下面是代码:
let initialDate = NSDate()
let components = NSDateComponents()
components.year = 1
components.month = 5
components.minute = 42
let laterDate = NSCalendar.currentCalendar().dateByAddingComponents(components, toDate: initialDate, options: nil)!
//Test the overloaded operator
let difference = laterDate - initialDate
//Results
println(difference.year) //Outputs: "1"
println(difference.month) //Outputs: "5"
println(difference.day) //Outputs: "0"
println(difference.hour) //Outputs: "0"
println(difference.minute) //Outputs: "42"
println(difference.second) //Outputs: "0"
这里有一些设置,不过大部分很好理解。我们先 初始化一个日期数据,它的值就是这个NSDate对象的创建日期,另外还有一个NSDateComponents对象包含了它自己的年月和分钟的属性值。 之后使用NSCalendar的dateByAddingComponents方法设置laterDate为1年5个月又42分钟之后的时间。然后测试重 载后的新功能“-”操作符,你会看到最后通过减法输出的结果刚好是我们设置的时间差。
我认为这样的重载还是有点用的,我们可以像平时使用数 学减法那样来计算。然而,这里隐藏某些假定的条件:首先我已经提到过关于NSCalendarUnit的Flag只是使用了一些而非全部;其次,我在重载 函数里明确使用了NSCalendar的当期日期(currentCalendar)在这里没有显示。最后它把计算结果difference的属性值都设 为了0,但我们其实并没有想使用其他的属性。不过就我所知,某些人也许会想到封装所有的属性来解决。
如果使用了普通的函数调用来代替重载运 算符,你可以很清楚使用了哪种格式的日期,选中哪些Flag,以及在diffrence里面可以发现哪些属性被设置过。这就是为什么我说重载运算符只是 “有点用”。原因就是它对代码的读者而言,想要知道函数中究竟隐藏了哪些假定条件的话只能扒开重载运算符的源码看了。
Equatable协议
Swift中的重载运算符里面还是有一些比较不错的地方。你可以通过重载"=="算符来实现对自定义类的比较。假如你想实现这一功能你就需要使用Equatable协议,Equatable协议主要应用于泛型编程(有关Swift的泛型编程可以参考这里)。如果你按照Equatable协议重载了"=="操作符,那么你无需再重载"!="操作符(因为“!=”的重载就是"=="的逻辑否)。
重载"=="的方式与其他的中缀运算的重载方式一致,就像我们在上面所提到的"-"重载一样:
//Globally scoped operator function
func == (left: Temperature, right: Temperature) -> Bool
{
if left.C == right.C
{
return true
}
else
{
return false
}
}
//Custom type itself
struct Temperature:Equatable
{
let C: Double
}
//Test
let tempOne = Temperature(C: 15)
let tempTwo = Temperature(C: 35)
let tempThree = Temperature(C: 15)
let OneTwoEquality = (tempOne == tempTwo) //Stores: false
let OneThreeEquality = (tempOne == tempThree) //Stores: true
现在我们可以使用“==”重载运算来比较两个Temperature实例了。如果要重载一个算符那么它必须要有一个对应的全局函数,甚至定义在类型之外。
Swift 中关于运算重载还有一个很不错的地方就是Comparable协议。如同遵照Equatable协议一样你在照着Comparable协议实现的时候你需 要重载一个“<”方法。另外如果你重载了"=="和">"运算符之后编译器会为你计算出其它几个运算符"!="、"<"、"& lt;="和">="的判定。可以看这里的一个例子,它同样也是Equatable协议的例子。
总结
本文中所有代码的测试环境均为Xcode 6.0.1。
前面我讨论了一下NSDate的减法,是因为它在被调用时隐藏了不少的假定条件。在这里提醒一下:当你在考虑编码中是否要实现重载运算符的时候可以想想这个示例。如果你想在代码里一直使用相同的unitFlag来重载实现日期的减法,你需要多写一些代码来考虑多种情况。
如果你想重载内建类型以及不想修改(或者无法修改)的类型的运算符重载,你可以在扩展里面添加这个重载函数。且这个重载函数需要为全局作用域,并放在你随便哪个扩展存放的文件里面。
有一些运算符是不能重载的,最为明显的就是赋值运算"="(一个等号)。就算你重载了,想一想赋值运算的使用频率,我不会对产生的错误有任何兴趣的。这里有Tammo Freese同学的一篇文章,你可以了解一下哪些运算符是不可以被重载的。
再议Swift操作符重载的更多相关文章
- c++ 操作符重载和友元
操作符重载(operator overloading)是C++中的一种多态,C++允许用户自定义函数名称相同但参数列表不同的函数,这被称为函数重载或函数多态.操作符重载函数的格式一般为: operat ...
- [置顶] operator overloading(操作符重载,运算符重载)运算符重载,浅拷贝(logical copy) ,vs, 深拷贝(physical copy)
operator overloading(操作符重载,运算符重载) 所谓重载就是重新赋予新的意义,之前我们已经学过函数重载,函数重载的要求是函数名相同,函数的参数列表不同(个数或者参数类型).操作符重 ...
- C++基础学习笔记----第十三课(操作符重载-下)
本节主要讲使用成员函数重载操作符,包括[],=,(),->四种操作符的重载以及&&和||的问题. 类的成员函数进行操作符重载 基本概念 类的成员函数也可以进行操作符的重载.类的普 ...
- C++ operator overload -- 操作符重载
C++ operator overload -- 操作符重载 2011-12-13 14:18:29 分类: C/C++ 操作符重载有两种方式,一是以成员函数方式重载,另一种是全局函数. 先看例子 # ...
- C#构造函数、操作符重载以及自定义类型转换
构造器 构造器(构造函数)是将类型的实例初始化的特殊方法.构造器可分为实例构造器和类型构造器,本节将详细介绍有关内容. 实例构造器 顾名思义,实例构造器的作用就是对类型的实例进行初始化.如果类没有显示 ...
- 15.C++-操作符重载
首先回忆下以前学的函数重载 函数重载 函数重载的本质为相互独立的不同函数 通过函数名和函数参数来确定函数调用 无法直接通过函数名得到重载函数的入口地址 函数重载必然发生在同一个作用域中 类中的函数重载 ...
- 用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- 操作符重载和隐式类型转换
C#中,某些类型会定义隐式类型转换和操作符重载.Unity中,有些对象也定义了隐式类型转换和操作符重载.典型情况有:UnityEngine.Object.UnityEngine.Object的销毁是调 ...
- 5.1 C++基本操作符重载
参考:http://www.weixueyuan.net/view/6379.html 总结: 操作符重载指的是将C++提供的操作符进行重新定义,使之满足我们所需要的一些功能. 长度运算符“sizeo ...
- 15.C++-操作符重载、并实现复数类
首先回忆下以前学的函数重载 函数重载 函数重载的本质为相互独立的不同函数 通过函数名和函数参数来确定函数调用 无法直接通过函数名得到重载函数的入口地址 函数重载必然发生在同一个作用域中 类中的函数重载 ...
随机推荐
- js跳转页面代码用法
一:window.location.href='https://www.baidu.com'; 需要加上http或者https,否则会查找项目内htm打开. 二:window.history.bac ...
- gdb 调试coredump文件过程
gdb 调试coredump文件过程: 第一步:首先需要一个进程的coredump文件,怎么搞出coredump文件呢? 1. ps -fax|grep 进程名称 找到 ...
- UGUI Toggle控件
今天我们来看看Toogle控件, 它由Toogle + 背景 + 打勾图片 + 标签组成的. 它主要用于单选和多选 属性讲解: Is On: 代表是否选中. Toogle Transition: 在状 ...
- 1 游戏逻辑架构,Cocos2d-x游戏项目创建,HelloWorld项目创建,HelloWorld程序分析,(CCApplicationProtocol,CCApplication,AppDeleg
1 游戏逻辑架构 具体介绍 A 一个导演同一时间仅仅能执行一个场景,场景其中,能够同一时候载入多个层,一个层能够可载多个精灵.层中亦能够加层. B 场景切换 sceneàaddChild(la ...
- NPOI兼容 excel2003,2007版本
根据项目需要,需要对excel进行导入导出,所以选择NPOI,优点在这里就不详细介绍了,下面进入正题. public int Import(string path) { IList<Studen ...
- mysql操作SQL语句
二.数据库操作SQL语句1.显示服务器上当前存在什么数据库SHOW DATABASES; 2.创建名称为rewin的数据库CREATE DATABASE rewin; 3.删除名称为rewin的数据库 ...
- [转]如何正确清理C盘
转自微软的Answers网站. 以下是推荐使用的方法,安全且不会误删有用的系统文件 1.尽量不要在C盘安装应用软件,在软件安装时,一般可以手动指定安装路径,您可以将软件指定安装到其他盘符. 在使用它们 ...
- visual studio 2015 修改类class 文件模板
第一步:找到模板文件 路径:C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\ItemTemplates\CSharp\C ...
- 000-C#基础
C#中数据类型的继承关系如下 System.Object |-------------System.ValueType | |-------System.Boolean | |-------Syste ...
- [Linked List]Insertion Sort List
Total Accepted: 59422 Total Submissions: 213019 Difficulty: Medium Sort a linked list using insertio ...