本篇纯属抬杠之作,之前我们提到了Swift的泛型Protocol使用associatedtype关键字,而不是使用<Type>语法的泛型参数。这其中有什么好处呢?

  我就这个问题搜索了一些回答,大体上提到两点:

  <Type>语法对Protocol没有意义,Protocol仅需要定义一个抽象的概念,具体的类型应该由实现的Class来明确,比如:

ClassWithInt<Int>: NumberProtocol
ClassWithDouble<Double>: NumberProtocol

  associatedtype可以用来给Protocol中特定Func添加泛型约束,而不是限定整个Protocol

protocol GeneratorType {associatedtype Elementpublic mutating func next() -> Self.Element?
}

  听上去还是有一定道理的,然后实践是检验事实的唯一标准。下面我们通过代码实例来和C#进行对比。首先拿出网上多被引用解释上述两个观点的Swift代码:

public protocol Automobile {associatedtype FuelTypeassociatedtype ExhaustTypefunc drive(fuel: FuelType) -> ExhaustType
}
public protocol Fuel {associatedtype ExhaustTypefunc consume() -> ExhaustType
}
public protocol Exhaust {init()func emit()
}public struct UnleadedGasoline<E: Exhaust>: Fuel {public func consume() -> E {print("...consuming unleaded gas...")return E()}
}
public struct CleanExhaust: Exhaust {public init() {}public func emit() {print("...this is some clean exhaust...")}
}
public class Car<F: Fuel,E: Exhaust>: Automobile where F.ExhaustType == E {public func drive(fuel: F) -> E {return fuel.consume()}
}public class Car1<F: Fuel>: Automobile {public func drive(fuel: F) -> F.ExhaustType {return fuel.consume()}
}

  具体的使用情况如下:

var car = Car<UnleadedGasoline<CleanExhaust>, CleanExhaust>()
car.drive(fuel: UnleadedGasoline<CleanExhaust>()).emit()var fusion = Car1<UnleadedGasoline<CleanExhaust>>()
fusion.drive(fuel: UnleadedGasoline<CleanExhaust>()).emit()

  转换成C#代码的话,有两种思路,首先是把泛型参数放到Interface层面:

    public interface Automobile<FuelType, ExhaustType>{ExhaustType Drive(FuelType fuel);}public interface Fuel<ExhaustType>{ExhaustType consume();}public interface Exhaust {void Emit();}public class UnleadedGasoline<Exhaust> : Fuel<Exhaust> where Exhaust : new(){public Exhaust consume(){Console.WriteLine("...consuming unleaded gas...");return new Exhaust();}}public class CleanExhaust : Exhaust{public void Emit(){Console.WriteLine("...this is some clean exhaust...");}}public class Car : Automobile<UnleadedGasoline<CleanExhaust>, CleanExhaust>{public CleanExhaust Drive(UnleadedGasoline<CleanExhaust> fuel){return fuel.consume();}}

  还可以模仿Swift对Automobile多做一层继承进行包装:

    public interface Car1<T1> : Automobile<UnleadedGasoline<T1>, T1> where T1 : new(){}public class SimpleCar : Car1<CleanExhaust>{public CleanExhaust Drive(UnleadedGasoline<CleanExhaust> fuel){return fuel.consume();}}

调用的时候没有什么太大的差别:

  var gaso = new UnleadedGasoline<CleanExhaust>();
  var car = new Car();car.Drive(gaso).Emit();  var simpleCar = new SimpleCar();simpleCar.Drive(gaso).Emit();

  和Swift比较不同的是,我们在Interface就代入了泛型参数。但是由于我们不能直接实例化Interface,所以并不能直接使用Automobile来减少一层继承关系。

  因为上述提到的使用associatedtype 的第一点理由见仁见智,这里不分高下。

  C#还有第二种思路,就是我也把泛型约束下放到Func层级:

    public interface Automobile{ExhaustType Drive<FuelType,ExhaustType>(FuelType fuel) where ExhaustType : new();}public interface Fuel{ExhaustType consume<ExhaustType>() where ExhaustType : new();}public class UnleadedGasoline : Fuel{public Exhaust consume<Exhaust>() where Exhaust : new(){Console.WriteLine("...consuming unleaded gas...");return new Exhaust();}}public class Car2 : Automobile{public CleanExhaust Drive<UnleadedGasoline, CleanExhaust>(UnleadedGasoline fuel) where CleanExhaust : new(){return  (fuel as Fuel).consume<CleanExhaust>();}}

C#的接口并不能定义构造函数。强行模仿起来还真是有点累啊。最终的使用也很简单:

    var fuel = new UnleadedGasoline();var car2 = new Car2();car2.Drive<UnleadedGasoline,CleanExhaust>(fuel).Emit();

  通篇比较下来,应该说Swift通过associatedtype 关键字和<Type>的混用,使得泛型的定义更为复杂也更灵活了。

  GitHub:

https://github.com/manupstairs/LearnSwift

https://github.com/manupstairs/LearnDotNetCore

转载于:https://www.cnblogs.com/manupstairs/p/5980850.html

Swift泛型Protocol对比C#泛型Interface相关推荐

  1. java 接口的泛型方法_Java泛型/泛型方法/通配符/泛型接口/泛型泛型擦出

    从JDK1.5以后引入了三大常用新特性:泛型.枚举(enum).注解(Annotation).其中JDK1.5中泛型是一件非常重要的实现技术,它可以帮助我们解决程序的参数转换问题.本文为大家详细介绍一 ...

  2. Java:高级之泛型概念引入,泛型可以设置多个类型参数,泛型继承和泛型接口实现,限制泛型可用类型,泛型通配的方式,泛型方法,泛型方法限制泛型可用类型

    目录页         泛型简介         泛型类         限制泛型可用类型         类型通配声明         泛型方法 问题引入 如果我们需要产生多个对象,每个对象的逻辑完 ...

  3. java 泛型集合应用_Java泛型集合的应用和方法

    展开全部 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以62616964757a686964616fe78988e69d8331333 ...

  4. Java泛型(1)--集合使用泛型Generic、自定义泛型、泛型在继承上的体现、通配符的使用

    文章目录 泛型的概念 集合中使用泛型 自定义泛型结构 泛型在继承上的体现 通配符的使用 泛型的概念 集合容器类在设计阶段/声明阶段不能确定这个容器实际存的是什么类型的对象,所以在JDK1.5之前只能把 ...

  5. java泛型与接口_Java泛型用于方法,类和接口

    什么是泛型? 型就是数据类型参数化.就是说原本定死的数据类型像方法中的形参一样,数据是不确定的,使用的时候由人传进去,泛型就是这样,数据类型不确定了.使用的时候再确定就可以了. 泛型的特点 是JDK1 ...

  6. java 反射和泛型-反射来获取泛型信息

    通过指定对应的Class对象,程序可以获得该类里面所有的Field,不管该Field使用private 方法public.获得Field对象后都可以使用getType()来获取其类型. Class&l ...

  7. java 怎么为泛型参数赋值_Java泛型讲解

    1. 概述在引入泛型之前,Java类型分为原始类型.复杂类型,其中复杂类型分为数组和类.引入范型后,一个复杂类型 就可以在细分成更多的类型. 例如原先的类型List,现在在细分成List, List等 ...

  8. java基本数据类型泛型_Java中的泛型

    泛型规范在JDK1.5版本中被添加,使用泛型机制编写的代码比起随意使用Object变量然后再进行强制类型转换的代码具有更高的安全性和可读性,同时也更为简洁.泛型对于集合类尤其有用,例如 ArrayLi ...

  9. .net java 泛型_Java高级特性泛型看这一篇就够了

    作者:qwer1030274531 出自:ITPUB博客 1.为什么我们需要泛型? 通过两段代码就可以知道为什么需要泛型 /*** * 没有泛型的时候实现加法 */public class NonGe ...

最新文章

  1. 由mysql分区想到的分表分库的方案
  2. 如何将S/4HANA系统存储的图片文件用Java程序保存到本地
  3. lambda 延迟执行_Java Lambdas和低延迟
  4. BitAdminCore框架更新日志20180529
  5. df python 增加数据_美国确诊超100万!教你用Python画出全球疫情动态图(附数据下载)...
  6. 指针变量的声明、地址相关运算--“*”和“”
  7. 【STM32F429的DSP教程】第14章 DSP统计函数-最大值,最小值,平均值和功率
  8. 平面设计配色方案有哪些
  9. CorelDRAW2023安装下载教程精简版矢量绘图软件
  10. 暗黑2符文之语大全_暗黑破坏神2符文之语一览,附符文镶嵌顺序和底材
  11. 查询出每一个雇员的姓名,工资,部门名称,工资在公司的等级及其领导的姓名,领导的工资,以及领导所相应的等级...
  12. java贪吃蛇代码idea_IntelliJ idea使用笔记 - 贪吃蛇学院-专业IT技术平台
  13. 日历 java 代码
  14. ArchSummit讲师专访:EMC研究院资深研究员陶隽谈实时数据分析
  15. 信息系统集成解决医院系统
  16. ISP算法----基本DPC算法实现代码
  17. 【5G之道】第六章:下行链路物理层处理
  18. linux软件实现看门狗,一个软件实现的Linux看门狗—soft_wdt
  19. 远程桌面连接软件轻松实现远程移动办公
  20. 在冷风中我凌乱了半小时,只因健康码刷不出来

热门文章

  1. Asp.Net中using的使用的方法(转)
  2. 如今的移动操作系统,写在2013年——android篇 by 伊一线天
  3. 6大主流开源SQL引擎总结,遥遥领先的是谁?
  4. linux下搭建FTP服务器
  5. linux系统在虚拟机中迁移的技术难点
  6. i++与++i的区别,使用实例说明
  7. 使用@Order调整配置类加载顺序
  8. MySQL中的information_schema
  9. python中other_Python other
  10. git push到GitHub的时候遇到! [rejected] master -> master (non-fast-forward)的问题