Swift 自定义运算符

Swift 自定义运算符

1. 运算符

Swift 提供了一组对于 C 或者 Objective-C 开发者来说十分熟悉的运算符,并且补充了一些新的(特别需要注意的是,区间运算符和空值合并(nil coalescing)运算符):

如下面这些运算符

符号 -
+
-
*
/
%
+=: 赋值增
-=: 赋值减
*=: 赋值乘
/= 赋值除
!
~ 按位取反
…… ……

2. 重载

Swfit 是可以重载运算符的,其能够让现有的运算符像 + 在其它的类型中起作用。

为了重载一个运算符,需要为运算符号简单的定义一个新的函数,并且要有适当的参数个数。

例如,重载 * 来让一个字符串重复某个特定的次数:

func * (left: String, right: Int) -> String {
  
    if right <= 0 {
        return ""
    }
    var result = left
    for _ in 1..<right {
        result += left
    }
    return result
}

print("a" * 6)//aaaaaa

然而,这是一个有争议的语言特性。

如下语句:

[1, 2] + [3, 4] // [1, 2, 3, 4]

两个数组相加,想得到 [1, 2, 3, 4],但重载以后:

func +(left: [Double], right: [Double]) -> [Double] {
   
    var sum = [Double](repeating: 0.0, count: left.count)
  
    for (i, _) in left.enumerated() {
        sum[i] = left[i] + right[i]
    }
    return sum
}

得到的是 [4.0, 6.0]

运算符重载的问题会造成:语意不清。在使用时,要注意具体应用,并避免重载。

  • 计算整数的和: 1 + 2 // 3
  • 计算浮点数的和: 1.0 + 2.0 // 3.0
  • 字符串连接: "a" + "b" // "ab"
  • 数组连接: ["foo"] + ["bar"] // ["foo", "bar"]

如果需要重载运算符要考虑多种情况,避免出现不可预见的bug.

3. 自定义运算符

自定义运算符,一般可以分三步

  • 1.定义优先级组

    如果需要自己设置优先级组,可以自己定义,使用precedencegroup关键字声明,如果不需要,可以省去。precedencegroup定义了一个操作符优先级别。操作符优先级的定义和类型声明有些相似,一个操作符比需要属于某个特定的优先级。Swift 标准库中已经定义了一些常用的运算优先级组,比如加法优先级 (AdditionPrecedence) 和乘法优先级 (MultiplicationPrecedence) 等,你也可以查看完整的列表。如果没有适合你的运算符的优先级组,你就需要像在例子中做的这样,自己指定方式和优先级顺序。

    precedencegroup CustomerPrecedence {
      /// 优先从左向右, left, right or none
      associativity: left
      higherThan: MultiplicationPrecedence//优先级,比乘法运算高
      // lowerThan: AdditionPrecedence // 优先级, 比加法运算低
      assignment: false // 是否是赋值运算
    }
    

    associativity
    定义了结合律,即如果多个同类的操作符顺序出现的计算顺序。比如常见的加法和减法都是 left

    higherThan
    运算的优先级,乘法运算是优先于加减运算的。除了 higherThan,也支持使用 lowerThan 来指定优先级低于某个其他组。

  • 2.设置优先级

    继承 CustomerPrecedence 优先级组,也可以继承已有优先级组 AdditionPrecedence等

    infix operator **: CustomerPrecedence 
    

    infix
    表示要定义的是一个中位操作符,即前后都是输入;其他的修饰子还包括 prefixpostfix,感兴趣的可以尝试一下;

  • 3.在扩展类里写实现,或者自定义类

    **运算符定义一个数的平方。

    extension Int {
    static func ** (lhs: Int, rhs: Int) -> Int {
        return Int(pow(Double(lhs), Double(rhs)))
     }
    }
    print(10**2)// 100
    
    

    字符串示例

    precedencegroup BLCustomerPrecedence {
    
      /// 优先从左向右, left, right or none
      associativity: left
      //    higherThan: MultiplicationPrecedence//优先级,比乘法运算高
      //    lowerThan: AdditionPrecedence       // 优先级, 比加法运算低
      assignment: false                   // 是否是赋值运算
      }
    
    infix operator ~~: BLCustomerPrecedence
    
    extension String {
    
      static func ~~ (left: String, right: String) -> String {
             return left + right
        }
    }
    print("12112"~~"~~")
    

    便捷写法:

    求一个数的平方根

    prefix operator √ // 默认 左->右 的优先级
    prefix func √ (number: Double) -> Double {
           return sqrt(number)
    }
    √4  // 2
    

需要注意的是,Swift 的操作符必须是全局部的,用static修饰。这就可能与其他 module 定义的操作符有冲突,这点需要特别注意。自定义操作符应该尽量避免重载,应简尽简,切禁写的太复杂,命名尽量规范,避免误解。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容

  • C++运算符重载-上篇 本章内容:1. 运算符重载的概述2. 重载算术运算符3. 重载按位运算符和二元逻辑运算符4...
    Haley_2013阅读 2,293评论 0 51
  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,745评论 2 9
  • Swift官方文档的词汇结构中, 有非常多的关键字, 它们被用于声明中、语句中、表达式中、类中、模式中, 还有以数...
    小宇宙_fly阅读 768评论 0 3
  • “别惹姨妈期的女生,她们都很暴躁。”不知从何而起,确又如此具有普适性。 一直是一个姨妈到来日子超级规律的女生,一直...
    Minna_0717阅读 142评论 0 0
  • 其实克兰德太太有她的苦衷,她编了一个关于她老公的桃色新闻,说是与一个法国的舞蹈家私奔了。它为克兰德太太赚得了...
    胡妙妙阅读 323评论 0 0