Swift泛型定义 同时限定T的类(class)和多协议(protocol)
https://blog.csdn.net/weixin_34054931/article/details/88027728
swift 可以定义模板函数,如:
func testFunc<T>(datas: [T]) -> T{
}
复制代码
这里有个T,使用指代类型的,这个方法定义出来,可以用来处理任意的数组:
let names = [String]()
testFunc(names)
传入String的数组,T就是String;传入Int的数组,T就是Int.这个方法就像是一个模板,有了它,可以复刻出许多个不同的版本。
问题1:我想要这个T是具有某个特定方法的
举个常用的例子:
比如写一个用来找最小值的方法,func min<T>(datas: [T]) -> T?,我肯定是希望它能处理数字、字符串、日期,甚至是自定义类的对象,那就需要这个被排序的数组里的对象,必须得实现一个比较的函数, 这个我才能知道那个大那个小,才能排序。而且我只需要这个比较函数就可以对所有类通用了。
比如可以写成:
func min<T>(datas: [T]) -> T?{
}
var min: T = datas.first!
for data in datas {
if data.compareTo(min) < 0{
min = data
}
}
return min
}
里面用了compareTo方法。我要怎么确定这个T一定是有这个方法的呢?
祭出法宝:protocol
联想:一些人困惑协议有什么用?跟block/闭包有什么区别?这里的功能就是闭包无法替代协议的,其实协议和委托是可以不一起行动的。
定义一个协议:
protocol Comparable : NSObjectProtocol{
- parameter other: 其他对象
- returns: 0 相等 -1 小于 1 大于
*/
func compareTo(other: Self) -> Int
}
然后把方法定义修改为:
func min<T:Comparable>(datas: [T]) -> T?
T后面限定了类型,指定了这个T是遵循类Comparable这个协议的,那么也就具有了compareTo这个方法。在我理解里,协议的核心就在这:表明某个类具有特定的方法/能力
问题2:多个协议怎么办?
假如我想处理的T类型是需要具有两个不同的能力,举个现实的例子:一个榨汁机,它接收的东西应该同时具有可被碾碎和出水两个特性,这两个特性是分开的,因为饼干不出水和椰子碾不碎。对应到代码,可悲碾碎是一个protocol里的一个方法,会出水是另一个protocol的方法。
多个协议只需要写成:
func min<T:protocol<testProtocol1,testProtocol2>>(datas: [T]) -> T?
把两个协议用protocol关键字装起来就好了。
问题3:如果我还想这个T是某个特定的类呢?
比如我想T是class1这个类的对象,同时遵循testProtocol1和testProtocol2,怎么写?
祭出法宝:where关键字
方法写成:
func findMinTemplateFunc<T : testCalss
把协议的限定方法where里面去,where还有其他用法,我也没太用过,就不说了。
这个需求看起来好像很难发生,但只需要想一个东西就有了:抽象类。swift/OC里没强掉这个概念,但是这个东西是存在的,比如CoreData里面的NSManageredObject,你会直接使用这个类来构造对象吗?肯定不会,肯定要建自己的数据实体,也就是NSManageredObject的子类来操作了。
当有了抽象类做父类的时候,你处理的都是子类,如果你写一个针对子类的模板方法,有些子类实现了testProtocol1,有些实现了testProtocol2,有些没有。这时,就必须类、协议同时限定才能达到效果。
最后贴段例子:
加入找出数组里最小值,每个值根据value1 \ value2 和rate做一段算法后的值来比较:
protocol testProtocol1: NSObjectProtocol {
protocol testProtocol2: NSObjectProtocol {
func value2() -> Int;
}
//类似虚类的东西,比如NSManagedObject这种类,是不可能直接使用它来构建对象的,肯定是要配合自己建的CoreData实体
class testCalss: NSObject {
var rate: Int? = 1
}
func findMinTemplateFunc<T : testCalss where T :protocol<testProtocol1,testProtocol2>>(datas: [T]) -> T?{
if datas.count == 0 {
return nil
}
var min : T = datas.first!
var minRealValue = min.value1() * 10 + min.value2() * 100
if let rate = min.rate {
minRealValue *= minRealValue * rate
}
for data in datas {
var realValue = data.value1() * 10 + data.value2() * 100
if let rate = data.rate {
realValue *= realValue * rate
}
if realValue < minRealValue {
min = data
minRealValue = realValue
}
}
return min
}
//例子
class subClass1: testCalss, testProtocol1, testProtocol2 {
func value1() -> Int {
return Int(arc4random() % 10)
}
func value2() -> Int {
return Int(arc4random() % 20)
}
}
class subClass2: testCalss, testProtocol1, testProtocol2 {
func value1() -> Int {
return Int(arc4random() % 100)
}
func value2() -> Int {
return Int(arc4random() % 200)
}
}
func runTest(){
var array1 = [subClass1]()
for _ in 0...99 {
array1.append(subClass1())
}
findMinTemplateFunc(array1)
var array2 = [subClass2]()
for _ in 0...99 {
array2.append(subClass2())
}
findMinTemplateFunc(array1)
}
runTest()
Swift泛型定义 同时限定T的类(class)和多协议(protocol)的更多相关文章
- Swift泛型协议的N种用法
They said "you should learn a new language every year," so I learned Swift. Now I learn ...
- Java泛型全解析【接口、类、封装类型】
目录 1.导读 2.为何需要泛型? 3.泛型的定义格式 3.泛型的好处 4.什么时候使用泛型? 5.泛型的擦除 6.泛型的补偿 7.泛型的应用 7.1[泛型类] ...
- 一文详解scala泛型及类型限定
今天知识星球球友,微信问浪尖了一个spark源码阅读中的类型限定问题.这个在spark源码很多处出现,所以今天浪尖就整理一下scala类型限定的内容.希望对大家有帮助. scala类型参数要点 1. ...
- Swift 泛型和闭包结合使用
通常在Swift中定义一个闭包来使用 typealias Closure= (Any?) -> () var tempClosure :Closure? /// 定义一个方法直接调用 func ...
- SpringCloud系列三:SpringSecurity 安全访问(配置安全验证、服务消费端处理、无状态 Session 配置、定义公共安全配置程序类)
1.概念:SpringSecurity 安全访问 2.具体内容 所有的 Rest 服务最终都是暴露在公网上的,也就是说如果你的 Rest 服务属于一些你自己公司的私人业务,这样的结果会直接 导致你信息 ...
- C++之enum枚举量声明、定义、使用与枚举类详解
C++之enum枚举量声明.定义.使用与枚举类详解 学习一个东西,首先应该指导它能做什么,其次去知道它怎么去做,最后知道为什么去这么做. 知其然知其所以然.不能冒进 ,一步一步的慢慢来.
- C++定义一个简单的Computer类
/*定义一个简单的Computer类 有数据成员芯片(cpu).内存(ram).光驱(cdrom)等等, 有两个公有成员函数run.stop.cpu为CPU类的一个对象, ram为RAM类的一个对象, ...
- django-自定义文件上传存储类
文件储存API:https://yiyibooks.cn/xx/django_182/ref/files/storage.html 编写自定义存储系统:https://yiyibooks.cn/xx/ ...
- 系统整理 精讲 swift 泛型
泛型是一种非常领会的语法,让我很是膜拜! 真是让人又爱又恨,学不懂的时候很抓狂 允许程序在函数,枚举,结构体,类中定义类型形参(类型可以动态改变) 每次使用可以传入不同类型的形参! Array< ...
随机推荐
- postgres登录失败Connection refused与SSL off失败
连接失败问题 使用postgres数据库连接工具测试,遇到两次失败 第一个登录失败问题 Connection to 192.168.XX.XX:5432 refused. Check that the ...
- day11-Python运维开发基础(迭代器与可迭代对象、高阶函数)
1. 迭代器与可迭代对象 # ### 迭代器 """ 迭代器: 能被next方法调用,并且不断返回下一个值的对象,是迭代器(对象) 特征:迭代器会生成惰性序列,它通过计算 ...
- 将varchar2类型字段改成clob类型
--增加临时新字段alter table base_temp add temp clob; --将需要改成大字段的项内容copy到大字段中update base_temp set temp=con ...
- [Tommas] ERP系统测试用例设计1(转)
问题: 1.如何进行ERP系统测试用例设计? 2.ERP系统测试用例设计过程? 3.ERP系统测试用例设计的方法? ERP系统本身是一种业务流程很复杂,单据报表众多,逻辑性很强的系统,质量保证方面很难 ...
- rapid-generator JAVA代码生成器
有感于马上要做个比较大的业务系统,想到那无止境的增删改查.粘贴复制,顿时脑后升起一阵凉风.于是想到个找或者写一个Java代码的生成器,这样在正常开发进度下,也能余下更多的时间去做些别的事情. 闲话少说 ...
- 【Luogu4448】 [AHOI2018初中组]球球的排列
题意 有 \(n\) 个球球,每个球球有一个属性值 .一个合法的排列满足不存在相邻两个球球的属性值乘积是完全平方数.求合法的排列数量对 \(10^9+7\) 取膜. \(n\le 300\) (本题数 ...
- Java并发编程之并发简介
操作系统中同时执行多个程序原因: 1.资源利用率:系统资源及硬件资源.当一个程序再等待另一个程序时,可以运行另一个程序,可提高资源利用率. 2.公平性:多个程序对计算机上的资源理论上具有同等的使用权. ...
- Linux:Shell-Bash基本功能
1.历史命令 history [选项] [历史命令保存文件] 选项:-c 清空历史命令 -w 把缓存中的历史命令写入历史命令保存文件 ~/.bash_history 历史命令默认保存1000条,可以 ...
- 学习进度-10 python爬虫
学习爬虫的第一个案例是小说爬虫. 小说爬虫首先是解析小说页面源代码,在页面源代码中可以看到小说每章节的内容链接 爬虫的代码: import requests import re url = 'http ...
- CSAPP读书笔记--第八章 异常控制流
第八章 异常控制流 2017-11-14 概述 控制转移序列叫做控制流.目前为止,我们学过两种改变控制流的方式: 1)跳转和分支: 2)调用和返回. 但是上面的方法只能控制程序本身,发生以下系统状态的 ...