余晖落尽暮晚霞,黄昏迟暮远山寻
本站
当前位置:网站首页 > 编程知识 > 正文

Swift 4.1 官方文档大全(第十七章)扩展(Extensions)

xiyangw 2022-12-04 09:48 15 浏览 0 评论

扩展

扩展为现有类,结构,枚举或协议类型添加新功能。 这包括扩展您无法访问原始源代码的类型(称为追溯建模)的功能。 扩展与Objective-C中的类别相似。 (与Objective-C类别不同,Swift扩展没有名称。)

Swift 4.1 官方文档大全(第十七章)扩展(Extensions)

Swift中的扩展可以:

添加计算的实例属性和计算的类型属性

定义实例方法和类型方法

提供新的初始化程序

定义下标

定义和使用新的嵌套类型

使现有类型符合协议

在Swift中,您甚至可以扩展协议以提供其需求的实现或添加符合类型可以利用的其他功能。 有关更多详细信息,请参阅协议扩展。

注意

扩展可以向类型添加新功能,但是它们不能覆盖现有功能。

扩展语法

用扩展关键字声明扩展名:

extension SomeType {

// new functionality to add to SomeType goes here

}

扩展可以扩展现有类型以使其采用一个或多个协议。 要添加协议一致性,您需要按照为类或结构编写协议名称的方式编写协议名称:

extension SomeType: SomeProtocol, AnotherProtocol {

// implementation of protocol requirements goes here

}

在添加扩展协议一致性中描述了以这种方式添加协议一致性。

可以使用扩展来扩展现有的泛型类型,如扩展泛型类型中所述。 您还可以扩展通用类型以有条件地添加功能,如扩展中使用通用Where子句中所述。

注意

如果您定义了一个扩展来为现有类型添加新功能,即使在定义扩展之前创建了新功能,新功能也可用于该类型的所有现有实例。

计算属性

扩展可以将计算的实例属性和计算的类型属性添加到现有类型。 此示例向Swift的内置Double类型添加了五个计算的实例属性,为使用距离单位提供基本支持:

extension Double {

var km: Double { returnself * 1_000.0 }

var m: Double { returnself }

var cm: Double { returnself / 100.0 }

var mm: Double { returnself / 1_000.0 }

var ft: Double { returnself / 3.28084 }

}

let oneInch = 25.4.mm

print("One inch is \(oneInch) meters")

// Prints "One inch is 0.0254 meters"

let threeFeet = 3.ft

print("Three feet is \(threeFeet) meters")

// Prints "Three feet is 0.914399970739201 meters”

这些计算出的属性表示Double值应被视为某个长度单位。虽然它们是作为计算属性实现的,但可以使用点语法将这些属性的名称附加到浮点字面值上,作为使用该文字值执行距离转换的一种方法。

在这个例子中,1.0的Double值被认为代表“一米”。这就是m计算属性返回self的原因 - 表达式1.m被认为是计算1.0的Double值。

其他单位需要将某些转换表示为以米为单位的值。一公里与1000米相同,因此km计算的属性将值乘以1_000.00以转换为以米为单位的数字。同样,一米有3.28084英尺,所以ft计算属性将底层Double值除以3.28084,将其从英尺转换为米。

这些属性是只读的计算属性,因此为简洁起见,它们不使用get关键字来表示。它们的返回值是Double类型的,可以在接受Double的任何地方用于数学计算:

letaMarathon = 42.km + 195.m

print("A marathon is \(aMarathon) meters long")

// Prints "A marathon is 42195.0 meters long"

注意

扩展可以添加新的计算属性,但不能添加存储的属性,或者将属性观察器添加到现有属性

初始化器(init)

扩展可以添加新的初始化器到现有的类型。这使您可以扩展其他类型以接受您自己的自定义类型作为初始化参数,或者提供附加的初始化选项,这些初始化选项不属于该类型原始实现的一部分。

扩展可以将新的便捷初始值设定项添加到类中,但不能将新的指定初始值设定项或去初始化项添加到类中。指定的初始化器和去初始化器必须始终由原始类实现提供。

注意

如果使用扩展将初始值设定项添加到为其所有存储属性提供默认值并且未定义任何自定义初始值设定项的值类型,则可以在扩展的初始值设定项中为该值类型调用默认初始值设定项和成员初始值设定项。

如果您已将初始值设定项作为值类型原始实现的一部分编写,则情况不会如此,如“初始值设定项的值类型委派”中所述。

下面的例子定义了一个自定义Rect结构来表示一个几何矩形。该示例还定义了两个名为Size和Point的支持结构,它们的所有属性都提供默认值0.0:

struct Size {

var width = 0.0, height = 0.0

}

struct Point {

varx = 0.0, y = 0.0

}

struct Rect {

var origin = Point()

var size = Size()

}

由于Rect结构为其所有属性提供默认值,因此它会自动接收默认初始值设定项和成员初始值设定项,如默认初始值设定项中所述。 这些初始化器可用于创建新的Rect实例:

let defaultRect = Rect()

let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),

size: Size(width: 5.0, height: 5.0))

您可以扩展Rect结构以提供一个额外的初始化程序,它需要一个特定的中心点和大小:

extension Rect {

init(center: Point, size: Size) {

let originX = center.x - (size.width / 2)

let originY = center.y - (size.height / 2)

self.init(origin: Point(x: originX, y: originY), size: size)

}

}

这个新的初始化器通过基于提供的中心点和大小值计算适当的原点开始。 初始化程序然后调用结构的自动成员初始化程序init(origin:size :),它将新的原点和大小值存储在相应的属性中:

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),

size: Size(width: 3.0, height: 3.0))

// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)

注意

如果您为扩展提供了新的初始化程序,则仍然有责任确保初始化程序完成后每个实例都完全初始化。

方法

扩展可以添加新的实例方法和类型方法到现有的类型。 以下示例将一个名为repetitions的新实例方法添加到Int类型中:

extension Int {

func repetitions(task: () -> Void) {

for_in0..<self {

task()

}

}

}

repetitions(task: ()方法采用type() - > Void的单个参数,该参数表示一个没有参数且不返回值的函数。

在定义了这个扩展之后,你可以调用任意整数的重复(task :)方法来执行多次任务:

3.repetitions {

print("Hello!")

}

// Hello!

// Hello!

// Hello!

mutating实例方法

添加了扩展的实例方法也可以修改(或改变)实例本身。 修改自身或其属性的结构和枚举方法必须将实例方法标记为变异,就像从原始实现中改变方法一样。

下面的例子为Swift的Int类型添加了一个名为square的新变异方法,它将原始值平方:

extension Int {

mutating func square() {

self = self * self

}

}

var someInt = 3

someInt.square()

// someInt is now 9

下标

扩展可以将新的下标添加到现有类型。 这个例子为Swift的内置Int类型添加了一个整数下标。 该下标[n]从数字右侧返回n位的十进制数字:

123456789 [0]返回9

123456789 [1]返回8

…等等:

extension Int {

subscript(digitIndex: Int) -> Int {

var decimalBase = 1

for_in 0..< digitIndex {

decimalBase *= 10

}

return (self / decimalBase) % 10

}

}

746381295[0]

// returns 5

746381295[1]

// returns 9

746381295[2]

// returns 2

746381295[8]

// returns 7

如果Int值对于所请求的索引没有足够的数字,则下标实现返回0,就好像该数字已用左边填充了零:

746381295[9]

// returns 0, as if you had requested:

0746381295[9]

嵌套类型

扩展可以将新的嵌套类型添加到现有的类,结构和枚举中:

extension Int {

enum Kind {

case negative, zero, positive

}

var kind: Kind {

switch self {

case 0:

return .zero

case let x where x > 0:

return .positive

default:

return .negative

}

}

}

本示例向Int添加了一个新的嵌套枚举。 这种枚举称为Kind,表示特定整数表示的数字种类。 具体而言,它表示数字是否为负数,零或正数。

此示例还向Int添加了一个新的计算实例属性,称为kind,它返回该整数的相应Kind枚举大小写。

嵌套的枚举现在可以与任何Int值一起使用:

func printIntegerKinds(_numbers: [Int]) {

for number in numbers {

switch number.kind {

case .negative:

print("- ", terminator: "")

case .zero:

print("0 ", terminator: "")

case .positive:

print("+ ", terminator: "")

}

}

print("")

}

printIntegerKinds([3, 19, -27, 0, -6, 0, 7])

// Prints "+ + - 0 - 0 + "

此函数printIntegerKinds(_ :)接受一个Int值的输入数组,并依次迭代这些值。 对于数组中的每个整数,函数会考虑该整数的种类计算属性,并打印适当的描述。

注意

number.kind已知是Int.Kind类型。 因此,所有的Int.Kind案例值都可以在switch语句中以简写形式写入,例如.negative而不是Int.Kind.negative。

相关推荐

spring利用spring.handlers解析自定义配置(spring validation 自定义)

一、问题我们在spring的xml配置文件里经常定义各种各样的配置(tx、bean、mvc、bean等等)。以及集成第三方框架时,也会看到一些spring之外的配置,例如dubbo的配置、securi...

「Spring源码分析」AOP源码解析(上篇)(spring源码深度解析(第2版))

前言前面写了六篇文章详细地分析了SpringBean加载流程,这部分完了之后就要进入一个比较困难的部分了,就是AOP的实现原理分析。为了探究AOP实现原理,首先定义几个类,一个Dao接口:1&nbs...

Spring 解析注册BeanDefinition这一篇就Over
Spring 解析注册BeanDefinition这一篇就Over

一、简介:学习过Spring框架的人一定都会听过Spring的IoC(控制反转)、DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC、...

2023-03-20 14:53 xiyangw

域、模块、空间、闭包,你真的懂了吗?(模块控制域与作用域的关系)

Javascript有一个特性叫做域。尽管对于初学者来说理解域是有难度的,但我会尽力用最简单的方式让你理解域。理解域能让你的代码更优秀,减少错误,及有助于你做出更强大的模式设计。什么是域域是在运行时,...

这一次搞懂Spring自定义标签以及注解解析原理
这一次搞懂Spring自定义标签以及注解解析原理

前言在上一篇文章中分析了Spring是如何解析默认标签的,并封装为BeanDefinition注册到缓存中,这一篇就来看看对于像context这种自定义标签是如...

2023-03-20 14:53 xiyangw

前端基础进阶(七)-前端工程师最容易出错的问题-this关键字
前端基础进阶(七)-前端工程师最容易出错的问题-this关键字

我们在学习JavaScript的时候,因为对一些概念不是很清楚,但是又会通过一些简洁的方式把它给记下来,那么这样自己记下来的概念和真正的概念产生了很强的偏差.当...

2023-03-20 14:52 xiyangw

深入K8s:守护进程DaemonSet及其源码分析(k8s 进程)
深入K8s:守护进程DaemonSet及其源码分析(k8s 进程)

建议学习:膜拜!阿里内部都在强推的K8S(kubernetes)学习指南,不能再详细了最近也一直在加班,处理项目中的事情,发现问题越多越是感觉自己的能力不足,...

2023-03-20 14:52 xiyangw

Spring 是如何解析 bean 标签的?(spring beans标签)
Spring 是如何解析 bean 标签的?(spring beans标签)

前情回顾上回「SpringIoC容器初始化(2)」说到了Spring如何解析我们定义的<bean>标签,代码跟进了一层又一层,跋山涉水,...

2023-03-20 14:52 xiyangw

快速了解JavaScript文本框操作(javascript文本框代码)
快速了解JavaScript文本框操作(javascript文本框代码)

HTML中使用<input>元素表示单行输入框和<textarea>元素表示多行文本框。HTML中使用的<input&...

2023-03-20 14:51 xiyangw

荐读|30道JavaOOP面试题,可以和面试官扯皮了
荐读|30道JavaOOP面试题,可以和面试官扯皮了

面试是我们每个人都要经历的事情,大部分人且不止一次,今天给大家准备了30道JavaOOP面试题,希望能够帮助到对Java感兴趣的同学,让大家在找工作的时候能够...

2023-03-20 14:51 xiyangw

源码系列——mybatis源码刨析总结,下(mybatis源码分析)
源码系列——mybatis源码刨析总结,下(mybatis源码分析)

接上文简答题一.1.Mybatis动态sql是做什么的?1.动态sql就是根据条件标签动态的拼接sql,包括判空,循环,拼接等2.哪些动态sql?动态sql大...

2023-03-20 14:50 xiyangw

Java面试题(第二弹)(java面试题及答案整理)
Java面试题(第二弹)(java面试题及答案整理)

1.抽象类和接口的区别?接口可以被多重implements,抽象类只能被单一extends接口只有定义,抽象类可以有定义和实现接口的字段定义默认为:public...

2023-03-20 14:50 xiyangw

mybatis3 源码深度解析-动态 sql 实现原理(sql数据库基础知识)
mybatis3 源码深度解析-动态 sql 实现原理(sql数据库基础知识)

大纲动态sql使用示例SqlSource和BoundSql以及实现类LanguageDriver以及实现类SqlNode以及实现类动态sql解...

2023-03-20 14:50 xiyangw

第43节 Text、Comment及CDATASection(第43节 Text、Comment及CDATASection)
第43节 Text、Comment及CDATASection(第43节 Text、Comment及CDATASection)

本内容是《Web前端开发之Javascript视频》的课件,请配合大师哥《Javascript》视频课程学习。文本节点用Text类型表示,包含的是可以按字面解释...

2023-03-20 14:49 xiyangw

Qt读写三种文件(qt读取文件数据并赋值给变量)

第一种INI配置文件.ini文件是InitializationFile的缩写,即初始化文件。除了windows现在很多其他操作系统下面的应用软件也有.ini文件,用来配置应用软件以实现不同用户的要...

取消回复欢迎 发表评论: