验证中...
gistfile1.txt
原始数据 复制代码
//我们在看一些协议的定义时,可能会注意到出现了首写字母大写的Self出现在类型的位置上
protocol IntervalType {
//Self出现在方法的参数类型及返回值类型上
func clamp(intervalToClamp:Self) -> Self
}
//重点:这么定义是因为协议其实本身是没有自己的上下文类型信息的。
//在声明协议的时候,我们并不知道最后究竟会是什么类型来实现这个协议,Swift中也不能在协议中定义泛型进行限制。
//而在声明协议时,我们希望在协议中使用的类型就是实现这个协议本身的类型的话,“就需要使用Self进行指代”。
//但是在这种情况下,Self不仅指代的是实现该协议的类型本身,也包括了这个类型的子类。
//从概念上来说,Self十分的简单,但是实际实现一个这样的方法却稍微要转个弯。
//我们假设要实现一个Copyable协议,满足这个协议的类型需要返回一个和接受方法调用的实例相同的拷贝。
protocol Copyable {
func copy () -> Self
}
//这是很直接明了的,它应该做的是创建一个和接受这个方法的对象同样的东西,然后将其返回,返回的类型不应该发生改变,所以写为Self.
//然后偿试实现一个MyClass来满足这个协议:
class MyClass:Copyable {
var num = 1
func copy() -> Self {
//TODO : 返回什么
//return
}
}
//我们一开始的时候会写类似这样的代码:(如下的写法是错误的。。。。)
func copy() -> Self {
let result = MyClass()
result.num = num
return result
}
//但是显然类型是有问题的,因为该方法要求返回一个抽象的,表示当前类型的Self,但是我们却返回了它的真实类型MyClass.
//重点:为了解决这个问题,我们在这里需要的是通过一个和当前上下文(也就是和MyClass)无关的,又能够指代当前类型的方式进行初始化。
//我们可以使用 type(of:)来获取“对象类型”,通过它也可以进一步进行初始化,以保证方法与当前类型上下文“无关”.
//这样不论是MyClass 还是它的子类,都可以正确地返回合适的类型满足Self的要求。
func copy() ->Self {
let result = type(of:self).init()
result.num = num
return result
}
//但是不幸,单单是这样还是无法通过编译,编译器提示我们如果想要构建一个Self类型的对象,需要有required关键字修饰的初始化方法
//这是因为Swift必须保证当前类和其子类都能响应这个init方法
//另一个解决的方案是在当前类类的声明前添加final 关键字,告诉编译器我们不再会有子类来继承这个类型。
//在这个例子中我们选择添加上required的init方法:
class MyClass:Copyable {
var num =1
func copy() -> Self {
let result = type(of:self).init()
result.num = num
return result
}
required init() {
}
}
//我们可以通过测试来验证一下行为的正确性:
let object = MyClass()
object.num = 100
let newObject = object.copy()
newObject.num = 1
print(object.num) // 1
print(newObject) // 100

评论列表( 1 )

64457_reyzhang
Reyzhang2010 2018-08-17 17:26

Self 是无关上下文的类型的抽象,所以Self在做为返回值返回时,不能将具体的类型返回,需要返回一个在上下文中无关的“对象类型”,并通过调用 初始化方法来返回,我们可以使用type(of:)来返回“对象类型”

你可以在登录后,发表评论

搜索帮助

12_float_left_people 12_float_left_close