作者: shanks
本周共整理了 5 个问题。涉及问题有:扩展协议问题,函数表示问题,final关键字问题,泛型问题和含有闭包的函数定义问题。
本周整理问题如下:
对应的代码都放到了 github 上,有兴趣的同学可以下载下来研究: 点击下载
点击打开问题原地址
以下代码会在 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
点击打开问题原地址
楼主在学习 Swift 语言的过程中,阅读了一些学习资料,比如官方文档。看到一些函数定义写成了这样: recordResponse(_:)
。不理解这样写表示什么意思。
在官方文档中,使用这种方式表达函数是一种约定,可以从官方文档 Functions 章节中看到很多这样的表示。刚开始看文档时候,也不太适应这种表示方式。也找不到为什么要这样表示,省略了很多函数的细节(比如没有返回值),把问题发到翻译组内部讨论群里面后,大家都一致认为,这是表达函数的一种约定的方式,至于怎么用这种表达式,下面这段话基本概括了用法:
大家在写博客时候,可以参照这种写法了,比如以下一些例子:
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
点击打开问题原地址
楼主定义了一个泛型结构体,声明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 中枚举高级用法及实践 ,值得一看!
点击打开问题原地址
有以下三种函数定义方式,有什么区别?
func myFunction() -> (()-> Int)
func myFunction1() -> (Void-> Int)
func myFunction2() -> Void-> Int
所以以上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()) }
}
这个例子中, myFuncA
和 myFuncB
是一样的。没有传入参数,返回一个闭包,这个闭包也没有传入参数,返回是另外一个闭包。而返回的闭包类型是 Int -> String
。
而 myFuncC
也是没有传入参数,返回一个闭包。这个闭包传入参数是一个闭包,返回是一个 String
。传入闭包类型是: () -> Int