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

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

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

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

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

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

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

public protocol Automobile {
    associatedtype FuelType
    associatedtype ExhaustType
    func drive(fuel: FuelType) -> ExhaustType
}
public protocol Fuel {
    associatedtype ExhaustType
    func 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

Swift泛型Protocol对比C#泛型Interface的更多相关文章

  1. swift:入门知识之泛型

    在尖括号里写一个名字来创建一个泛型函数或者类型 例如<T>.<Type> 可以创建泛型类.枚举和结构体 在类型后使用where来指定一个需求列表.例如,要限定实现一个协议的类型 ...

  2. Java泛型和集合之泛型介绍

    在声明一个接口和类的时候可以使用尖括号带有一个或者多个参数但是当你在声明属于一个接口或者类的变量的时候或者你在创建一个类实例的时候需要提供他们的具体类型.我们来看下下面这个例子 List<Str ...

  3. Java基础----Java---集合框架---泛型、泛型方法、静态方法泛型、泛型接口、泛型限定、泛型类

    泛型:jdk1.5后的新特性,用于解决安全问题,是一个安全机制. 好处: 1.将运行时的异常出现问题classcastException.转移到了编译时期.方便程序员调试解决问题,让运行事情问题减少, ...

  4. Java泛型三:Java泛型详解

    原文地址https://www.cnblogs.com/lzq198754/p/5780426.html 1.为什么需要泛型 泛型在Java中有很重要的地位,网上很多文章罗列各种理论,不便于理解,本篇 ...

  5. Java泛型四:Java泛型总结

    原文地址https://www.cnblogs.com/lwbqqyumidi/p/3837629.html 一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下面这段简短的代码: 1 publ ...

  6. 牛客网Java刷题知识点之泛型概念的提出、什么是泛型、泛型在集合中的应用、泛型类、泛型方法、泛型接口、泛型限定上限、泛型限定下限、 什么时候使用上限?泛型限定通配符的体现

    不多说,直接上干货! 先来看个泛型概念提出的背景的例子. GenericDemo.java package zhouls.bigdata.DataFeatureSelection; import ja ...

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

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

  8. Java 泛型 协变式覆盖和泛型重载

    Java 泛型 协变式覆盖和泛型重载 @author ixenos 1.协变式覆盖(Override) 在JDK 1.4及以前,子类方法如果要覆盖超类的某个方法,必须具有完全相同的方法签名,包括返回值 ...

  9. java泛型基础、子类泛型不能转换成父类泛型

    参考http://how2j.cn/k/generic/generic-generic/373.html 1.使用泛型的好处:泛型的用法是在容器后面添加<Type>Type可以是类,抽象类 ...

随机推荐

  1. 打造Ubuntu下Java开发环境

    一.了解JDK 不同的java软件和类库对jdk有不同要求,在了解如何安装Java之前,让我们快速地了解JRE.OpenJDK和Oracle JDK之间的不同之处. JRE(Java Runtime ...

  2. 用JQ仿造百度书籍预售页面的单屏滚页效果

    今天的项目需要做到一个介绍页面,我主动提出走单屏滚页的风格,毕竟交互性好,逼格也高,具体效果可以参照百度知道书籍预售页面. 其实现效果就大概是这样的: 还是老样子,所有步骤文件可以从我的Github上 ...

  3. STC12C5A60S2笔记1(管脚定义)

    STC12C5A60S2管脚定义 管脚1:标准IO口P1.0.ADC0 模数转换通道0.CLKOUT2 波特率发生器的时钟输出 管脚2:标准IO口P1.1.ADC1 模数转换通道1 管脚3:标准IO口 ...

  4. 每周一书-2016年8月15日到21日(bootstrap基础教程)获奖读者公布

    本次赠书 由微信昵称为“………….”的网友以10个赞获得. 请这位网友,订阅号回复你的联系方式,明天给你邮递这本书.谢谢!同时感谢<把时间当朋友>的获奖者“永梅”为<bootsrap ...

  5. 使用Location对象查询字符串参数

    location是BOM中最有用的对象之一: 1.它提供了与当前窗口中加载的文档有关的信息: 2.他还提供了一些导航功能. location对象的属性有: hash, host, hostname, ...

  6. 渣渣小本求职复习之路每天一博客系列——Unix&Linux入门(5)

    前情回顾:昨天简单地介绍了一下如何使用vi编辑器,例如命令模式和插入模式的切换,以及一些简单命令的讲解. —————————————————————————直接就开始吧———————————————— ...

  7. sourcesafe.light 开源项目启动

    sourcesafe.light 源于一个2D独立砖块沙盒游戏. 在这个游戏的设计中碰到了一个瓶颈:这个游戏想把玩家变成一个个neo,在矩阵世界中没有什么不可以修改. 这个游戏要跨平台,玩家的修改操作 ...

  8. 浮动ip

    浮动ip 其实就是动态ip, 静态IP是固定不变的,不管你用不用这个IP上网,这个IP都是属于你的动态IP则是在使用的时候由DHCP服务器临时分配给你的,不用则不分配在网络中如果设置了一部分静态IP地 ...

  9. js笔记——js里的null和undefined

    以下内容摘录自阮一峰的<语法概述 -- JavaScript 标准参考教程(alpha)>章节『5.null和undefined』,以做备忘. null与undefined都可以表示&qu ...

  10. Atitit dsl exer v3 qb3 新特性

    Atitit dsl exer v3 qb3 新特性 /atiplat_cms/src/com/attilax/dsl/DslParser.java V3 支持typeed参数,与简化的notyp参数 ...