转载

每周 Swift 社区问答 2016-03-09(第十二期)

作者: shanks

本周共整理了 5 个问题。涉及问题有:扩展协议问题,函数表示问题,final关键字问题,泛型问题和含有闭包的函数定义问题。

本周整理问题如下:

  • Extending Protocols With Default Implementation with Enums crashes Xcode
  • What does _: mean in Swift?
  • swift difference between final var and non-final var | final let and non-final let
  • Strange generics behavior in swift
  • Parentheses in Function and Closure

对应的代码都放到了 github 上,有兴趣的同学可以下载下来研究: 点击下载

Question1: Extending Protocols With Default Implementation with Enums crashes Xcode

点击打开问题原地址

问题描述

以下代码会在 extension 部分挂掉,playground 会弹出错误提示:Communication with the playground service was interrupted unexpectedly.楼主的本意是想给 specialAbility 提供一个默认值。

enum Ability {
case Flying
case Running
case Swimming
case Hiding
}

//All animals will conform to this
protocol Animal {
var name: String { get }
var specialAbility: Ability { get }
}

struct Dog: Animal {
var name: String
var specialAbility: Ability
}

let rex = Dog.init(name: "Rex", specialAbility: .Flying)

// 以下代码会crash
extension Animal where Self: Dog {
var specialAbility: Ability { return .Running }
}

问题解答

从 crash 的提示信息,看不出来是什么错,不知道苹果会不会在3.0修复这些提示不准确的问题。问题是由扩展 Animal 协议造成的, where 语句的约束条件,不能是一个具体的类,只能是协议。而 Dog 是具体的类, where 的知识点可以查看官方翻译教程: Where 子句 。

要解决默认值的问题,新增一个指定构造器即可:

)

extension Dog {
init(name: String) {
self.specialAbility = .Running
self.name = name
}
}

let rex1 = Dog.init(name: "Rex")
rex1.specialAbility

Question2: What does _: mean in Swift?

点击打开问题原地址

问题描述

楼主在学习 Swift 语言的过程中,阅读了一些学习资料,比如官方文档。看到一些函数定义写成了这样: recordResponse(_:) 。不理解这样写表示什么意思。

问题解答

在官方文档中,使用这种方式表达函数是一种约定,可以从官方文档 Functions 章节中看到很多这样的表示。刚开始看文档时候,也不太适应这种表示方式。也找不到为什么要这样表示,省略了很多函数的细节(比如没有返回值),把问题发到翻译组内部讨论群里面后,大家都一致认为,这是表达函数的一种约定的方式,至于怎么用这种表达式,下面这段话基本概括了用法:

  • 简单的说,函数签名里每个冒号都代表一个参数,每个参数都要有个外部参数名写在冒号前面,写_代表不要外部参数名. 参数名都是自动生成,默认情况下第一个参数不生成外部参数名

大家在写博客时候,可以参照这种写法了,比如以下一些例子:

  • sayHello(_:):传入一个参数
  • print(_:separator:terminator:):传入3个参数

Question3:swift difference between final var and non-final var | final let and non-final let

点击打开问题原地址

楼主的问题是关于 final 关键字的,带有 final 修饰符的变量和没有带的变量区别是什么?


var someVar = 5
final var someFinalVar = 5


let someLet = 5
final let someFinalLet = 5

问题解答

final 关键字主要用来修饰类和类中的属性、方法或者下标。子类继承时,不能重写父类中带有 final 修饰的属性、方法或者下标。如果 final 修饰的是类,那么此类不能被继承。

// 没有final修饰属性的情况
class A {
var x: Int {return 5}
}
class B : A {
override var x: Int {return 3}
}
var b = B()
assert(b.x == 3)

// 有final修饰的情况,报错
class A {
final var x: Int {return 5}
}
class B : A {
// 此处报错
override var x: Int {return 3}
}

更多 final 的细节,可以看看喵神关于 final 的 单独一篇tips

Question4: Swift array of generics

点击打开问题原地址

问题描述

楼主定义了一个泛型结构体,声明2个变量后,想把这2个变量塞到一个数组里面去,数组定义为 [Thing] ,编译报错。

struct Thing<T> {
}

let intThing = Thing<Int>()
let stringThing = Thing<String>()

// 编译错误:Cannot convert value of type 'Thing<Int>' to expected type 'Thing'
let things: [Thing] = [intThing, stringThing]

//: ### 问题解答

Thing 是一个泛型结构体,不能直接使用 [Thing] 表明一个数组。只能通过万能的 Any 来符合编译器的规则。不过这样做,显然就不能直接使用 Thing 里面的方法了,得做一下转换:

let things: [Any] = [intThing, stringThing]

var intThing1 = things[0] as! Thing<Int>

如果想要直接 [Thing] 这样的语法,可以使用枚举, 而使用枚举,就不能使用泛型了:

enum Thing {
case Text(String)
case Integer(Int)
}
let thingWithText = Thing.Text("Hello world")
let thingWithInt = Thing.Integer(123)

let things = [thingWithText, thingWithInt]

things.forEach { (thing) -> () in
switch thing {
case .Text(let text): print(text)
case .Integer(let integer): print(integer)
}
}

翻译组翻译了一篇关于枚举使用的很详细的文章: Swift 中枚举高级用法及实践 ,值得一看!

Question5: Parentheses in Function and Closure

点击打开问题原地址

问题描述

有以下三种函数定义方式,有什么区别?

func myFunction() -> (()-> Int)

func myFunction1() -> (Void-> Int)


func myFunction2() -> Void-> Int

问题解答

  • () 和 Void 是一样的,2种不同的写法而已。看你喜欢,Swift 中比较常用 ()。
  • -> 操作符是右关联的,也就是说,多个 -> 连接在一起时候,编译器优先解析右边的。

所以以上3个定义是一样的。第一个和第二个虽然加了括号,优先处理最右边的,但是因为->是右关联的,所以加括号和不加括号是一样的。

这3个表达式表示的意思是:定义一个函数,没有传入参数,返回一个闭包, 闭包的类型是 () -> Int

楼下还举了一个更复杂的例子加深理解:

func myFuncA() -> () -> Int -> String {
return { () -> Int -> String in return { (i: Int) -> String in String(i) } }
}

func myFuncB() -> () -> (Int -> String) {
return { () -> Int -> String in return { (i: Int) -> String in String(i) } }
}

func myFuncC() -> (() -> Int) -> String {
return { (f: () -> Int) in String(f()) }
}

这个例子中, myFuncAmyFuncB 是一样的。没有传入参数,返回一个闭包,这个闭包也没有传入参数,返回是另外一个闭包。而返回的闭包类型是 Int -> String

myFuncC 也是没有传入参数,返回一个闭包。这个闭包传入参数是一个闭包,返回是一个 String 。传入闭包类型是: () -> Int

原文  http://swift.gg/2016/03/09/swift-qa-2016-03-09/
正文到此结束
Loading...