接口和类方法中的 SELF
接口和类方法中的 SELF
由 王巍 (@ONEVCAT) 发布于 2015/06/10
我们在看一些接口的定义时,可能会注意到出现了首字母大写的 Self
出现在类型的位置上:
protocol IntervalType {
//...
/// Return `rhs` clamped to `self`. The bounds of the result, even
/// if it is empty, are always within the bounds of `self`
func clamp(intervalToClamp: Self) -> Self
//...
}
比如上面这个 IntervalType
的接口定义了一个方法,接受实现该接口的自身的类型,并返回一个同样的类型。
这么定义是因为接口其实本身是没有自己的上下文类型信息的,在声明接口的时候,我们并不知道最后究竟会是什么样的类型来实现这个接口,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
,这导致了无法编译。也许你会尝试把方法声明中的 Self
改为 MyClass
,这样声明就和实际返回一致了,但是很快你会发现这样的话,实现的方法又和接口中的定义不一样了,依然不能编译。
为了解决这个问题,我们在这里需要的是通过一个和当前上下文 (也就是和 MyClass
) 无关的,又能够指代当前类型的方式进行初始化。希望你还能记得我们在对象类型中所提到的 dynamicType
,这里我们就可以使用它来做初始化,以保证方法与当前类型上下文无关,这样不论是 MyClass
还是它的子类,都可以正确地返回合适的类型满足 Self
的要求:
func copy() -> Self {
let result = self.dynamicType()
result.num = num
return result
}
但是很不幸,单单是这样还是无法通过编译,编译器提示我们如果想要构建一个 Self
类型的对象的话,需要有 required
关键字修饰的初始化方法,这是因为 Swift 必须保证当前类和其子类都能响应这个 init
方法。在这个例子中,我们添加上一个 required
的 init
就行了。最后,MyClass
类型是这样的:
class MyClass: Copyable {
var num = 1
func copy() -> Self {
let result = self.dynamicType()
result.num = num
return result
}
required init() {
}
}
我们可以通过测试来验证一下行为的正确性:
let object = MyClass()
object.num = 100
let newObject = object.copy()
object.num = 1
println(object.num) // 1
println(newObject.num) // 100
而对于 MyClass
的子类,copy()
方法也能正确地返回子类的经过拷贝的对象了。
另一个可以使用 Self
的地方是在类方法中,使用起来也十分相似,核心就在于保证子类也能返回恰当的类型。
接口和类方法中的 SELF的更多相关文章
- Delphi接口的底层实现(接口在内存中仍然有其布局,它依附在对象的内存空间中,有汇编解释)——接口的内存结构图,简单清楚,深刻 good
引言 接口是面向对象程序语言中一个很重要的元素,它被描述为一组服务的集合,对于客户端来说,我们关心的只是提供的服务,而不必关心服务是如何实现的:对于服务端的类来说,如果它想实现某种服务,实现与该服务相 ...
- Java 私有接口 【类中嵌套接口】
1.前言 接口十分常用,能规范实现类的命名 和 实现多个实现类的向上转型成统一类型 ,但是接口的修饰符只能是 public吗? 当然不是,可以是private , 难道是像这样? 显然不可以,已经报错 ...
- Java中接口和Sala中的特质的区别?
1.先要区分是Java中哪个版本的接口,因为Java中不同版本接口是不一样2.Java8之前的接口(不包含Java8),这个版本的接口只能属性和抽象方法,和Scala中的特质有完全的不用因为Scala ...
- 老猿学5G扫盲贴:中移动的5G计费架构中Nchf'服务化接口以及CHF中的AGF
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.关于Nchf' 在中移动企标中出现了在3GPP ...
- C# 用SoapUI调试WCF服务接口(WCF中包含用户名密码的验证)
问题描述: 一般调试wcf程序可以直接建一个单元测试,直接调接口. 但是,这次,我还要测试在接口内的代码中看接收到的用户名密码是否正确,所以,单一的直接调用接口方法行不通, 然后就想办法通过soapU ...
- 对接第三方支付接口-获取http中的返回参数
这几天对接第三方支付接口,在回调通知里获取返回参数,有一家返回的json格式,请求参数可以从标准输入流中获取. //1.解析参数 , 读取请求内容 BufferedReader br; String ...
- SpringMVC框架下实现JSON(类方法中回传数据到jsp页面,使用jQuery方法回传)
JSON的实现,即将需要的数据回传到jsp页面: 1>.加入实现Json的三个架包到lib中:2>.目标方法上边加入注解,需要返回的值3>.在jsp页面中书写jQuery方法: ec ...
- IOS创建目录接口createDirectoryAtPath:withIntermediateDirectories:中参数attributes的设置
在应用程序执行时,经常需要本地化保存一些重要的数据,这时就有可能需要创建一些目录.Objective-C提供了一个非常强大的创建目录的接口: - (BOOL)createDirectoryAtPath ...
- python编程 之 PyMysql包接口,python中如何使用数据库
1,环境介绍 要求:使用数据库TESTDB.EMPLOYMENT EMPLOYEE表字段为 FIRST_NAME, LAST_NAME, AGE, SEX 和 INCOME. 2,基本用法: impo ...
随机推荐
- P5137 polynomial(分治)
传送门 神仙--这题有毒-- 一直在那里考虑没有逆元怎么办然后考虑解exgcd巴拉巴拉 最后只好看题解了 而且这题龟速乘都不行--得用代码里那种叫人半懂不懂的方式取模-- //minamoto #in ...
- 指向函数的指针和block
原文网址: http://www.cnblogs.com/cxbblog/p/3841226.html 一:block基础知识 block基础知识 基本概念:block是用来保存一段代码的:^:是bl ...
- BZOJ1102(搜索)
随便写一下的搜索,别的OJ深搜就过了,强大的BZOJ成功栈溢出RE了我并使我屈服地用广搜过掉,第一行手动开栈惨遭无视. 广搜: #pragma comment(linker, "/STACK ...
- 转 造成ORA-01843 无效的月份的一些原因
- Solr查询中涉及到的Cache使用及相关的实现【转】
转自:http://www.cnblogs.com/phinecos/archive/2012/05/24/2517018.html 本文将介绍Solr查询中涉及到的Cache使用及相关的实现.Sol ...
- webstock学习
1.WebSocket是HTML5中出出现的新技术,有着web TCP之称,这也是为了适应现在实时传输数据的趋势,在这之前一般采用两种方法进行实时数据交换. 轮询机制,其中又包括长轮询. ①短轮询是指 ...
- user-select详解
语法: user-select:none | text | all | element 默认值:text 适用于:除替换元素外的所有元素 继承性:无 动画性:否 计算值:指定值 取值: none: 文 ...
- IP Addresses of Google Global Cache
Bulgaria 93.123.23.1 93.123.23.2 93.123.23.3 93.123.23.4 93.123.23.5 93.123.23.6 93.123.23.7 93.123. ...
- ubuntu中使用eclipse开发android,logcat显示问题
〜/工作区/ .metadata / .plugins / org.eclipse.core.runtime / .settings / com.android.ide.eclipse.ddms.pr ...
- 百度地图 v2.1.3申请KEY Android签名证书的sha1值
今天研究下百度地图,没想到第一步就遇到了问题,升级2.13后,需要Android签名证书的sha1值,网上看了下,发现遇到这问题的童鞋还是很多,官方说的两种方法: 第一种:使用keytool keyt ...