Swift 冷门语法知识

本来这篇文章的标题是“如何写一个不安全的构造器”,但后面查资料的时候又发现了一些很好玩的东西,就一次性写成一篇出来,跟大家分享一下 Swift 里的几个 best pratice:

  • 带关联值的 Enum 的构造器
  • strongSelf 的另一种写法
  • 如何在 Swift 里写一个不安全的构造器
  • mutating 函数的定义

带关联值的 Enum 的构造器

写 Swift 的人应该很熟悉带关联值的枚举(Enumeration with Associated Value),例如原生的 Optional,错误处理的 Result 库等等,但在我尝试自定义枚举的构造器时遇到了这样的问题:

enum CustomOptional<Wrapped> {
    case value(Wrapped)
    case none
    
    init(value: Wrapped) {
        return .value(value) 
        // error: 'nil' is the only return value /
        // permitted in an initializer
    }
}

错误提示是构造器里只能够返回 nil,但如此一来我们就好像没有办法把构造器实现出来了。我想起在使用 Result 的时候有用到过它的构造器,查阅之后,发现正确的做法应该是这样的:

enum CustomOptional<Wrapped> {
    case value(Wrapped)
    case none
    
    init(value: Wrapped) {
        self = .value(value)
    }
}

顺带说一句,所有的值类型都支持这种写法。

出处:Result — Swift type modelling the success/failure of arbitrary operations

strongSelf 的另一种写法

之前我就写过一篇文章来讲这个,之所以再提一次,一方面是为了文章的完整性,另一方面就是为了下文的另一个语法做铺垫。

从 OC 带过来的命名方式,会让我们在闭包里这么去写 strongSelf:

block = { [weak self] in
    guard let strongSelf = self else { return }
    ... other code ...
}

strongSelf 在代码里的出现其实会有点突兀,我会更喜欢利用 Swift 一种语法,让代码变得统一:

block = { [weak self] in
    guard let `self` = self else { return }
    ... other code ...
}

这里声明了一个局部变量 self,让我们可以直接用来将捕获的 weak self 解包出来,由于 self 是系统关键字,使用 ` 包住关键字,可以让编译器把它看做是一个正常的变量名称。

然后我们在闭包里使用 self 时,就不必考虑它是否会产生循环引用的问题,别的地方的代码也可以很方便地复制粘贴过来,不用把 self 全部都改为 strongSelf

出处:忘了😒

Update 2017.08.24:

掘金里有位大神在评论里提醒我,原来这是一个编译的 bug,提案 SE-0079 很详细地讲了这件事情,但目前这个 bug 还没有修复,按照上面的方法去写就可以了。

如果这个 bug 被修复了的话,就可以没必要加上 `,可以直接声明局部变量 self:

block = { [weak self] in
    guard let self = self else { return }
    ... other code ...
}

如何在 Swift 里写一个不安全的构造器

开头我提到了这篇文章原本的标题是叫做“如何写一个不安全的构造器”,其实我是在写这篇文章的时候才发现了上面的语法,之前我是用了另外一种比较 dirty 的方式去做的:

enum CustomOptional<Wrapped> {
    case value(Wrapped)
    case none
    
    static func `init`<Wrapped>(value: Wrapped) -> CustomOptional<Wrapped> {
        return .value(value)
    }
}

很早的时候我就尝试过定义一个名为 init 的 static 函数,得到的是这样的提示 error: keyword 'init' cannot be used as an identifier here,也就是说 init 作为系统关键字不能在这里使用,那么很简单,用 ` 把它包住就行了。

这么定义 init 方法的话,在调用时也可以像正常的构造器那样省略掉 init:

let _ = CustomOptional(value: "I'm a String")

这种“构造器”的定义和实现都很灵活,可以返回任何类型,内部实现也不需要遵守那么多规则。这可能在一些我意想不到的场景下会有用吧,但我暂时没有想到,如果你恰好用到了这个小技巧,请务必发个邮件告诉我,我很好奇具体的使用场景。

出处:kemchenj

mutating 函数的定义

定义值类型的时候,同一个函数,我们经常需要定义 mutating 和 non-mutating 两个版本:

func sorted() -> Array { ... }

mutating func sort() { ... }

但绝大部分情况下这两个函数的实现基本上都是一样的,这个时候我们就可以考虑复用其中一个,减少重复代码:

func sorted() -> Array { ... }

mutating func sort() { 
    self = sorted()
}

之所以可以这样写,是因为 mutating 意味着函数会对值自身进行修改:

self.property = value

// 等价于

var newStruct = self
newStruct.property = value
self = newStruct

出处:Swift Talk #21 Structs and Mutation

最后

我想推荐一下这个视频,主要是讲 Swift 里如何构建高效的 Collection 类型,20分钟的长度,看完之后对于 objc.io 的那本书动心了,我基础很差也基本上看懂了里面的内容,讲得真的很不错,里面平衡二叉树的实现让我再一次强烈地感受到 Swift 的简洁。

觉得文章还不错的话可以关注一下我的博客

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

推荐阅读更多精彩内容