Swift泛型协议的N种用法

By admin in 4858.com on 2019年4月28日

  本篇纯属抬杠之作,在此之前大家提到了斯维夫特的泛型Protocol使用associatedtype关键字,而不是应用<Type>语法的泛型参数。那之中有怎么着好处吗?

  本篇纯属抬杠之作,在此以前大家提到了斯威夫特的泛型Protocol使用associatedtype关键字,而不是采用<Type>语法的泛型参数。这之中有怎么样好处吗?

  They said “you should learn a new language every year,” so I 
learned Swift. Now  I  learn a new language every two weeks!

  They said “you should learn a new language every year,” so I 
learned Swift. Now  I  learn a new language every two weeks!

  小编就以此难点查找了某些答应,大要上关系两点:

  我就那个主题材料查找了壹部分回复,大要上提到两点:

  这几个笑话绝对是自个儿看过的斯威夫特被黑的最惨的二回!所以明日我们来学习一下Swift的泛型。

  那个笑话相对是本人看过的Swift被黑的最惨的3次!所以今天我们来上学一下Swift的泛型。

  <Type>语法对Protocol没风趣,Protocol仅须要定义多少个华而不实的定义,具体的品种应该由落成的Class来明显,比如:

  <Type>语法对Protocol没有趣,Protocol仅必要定义多少个空洞的定义,具体的项目应该由完结的Class来明显,比如:

  Swift的泛型有点不敢相信 不可能相信,针对Class和Function,都是由此<Type>来定义,和C#1摸同样,一样也有where关键字展衡水锁。

  Swift的泛型有点不敢相信 不能相信,针对Class和Function,都以因而<Type>来定义,和C#1摸同样,一样也有where关键字展德州锁。

ClassWithInt<Int>: NumberProtocol
ClassWithDouble<Double>: NumberProtocol
ClassWithInt<Int>: NumberProtocol
ClassWithDouble<Double>: NumberProtocol
func swapTwoValues<T>(inout a: T, inout _ b: T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

class CanPrintBase<T> {
    func PrintType(output: T) -> Void {}
}
func swapTwoValues<T>(inout a: T, inout _ b: T) {
    let temporaryA = a
    a = b
    b = temporaryA
}

class CanPrintBase<T> {
    func PrintType(output: T) -> Void {}
}

  associatedtype能够用来给Protocol中特定Func增多泛型约束,而不是限量整个Protocol

  associatedtype能够用来给Protocol中特定Func增多泛型约束,而不是限量整个Protocol

  可是面对Interface,也正是Swift里的Protocol,必要使用associatedtype关键字来定义泛型:

  但是面对Interface,也等于Swift里的Protocol,须求接纳associatedtype关键字来定义泛型:

protocol GeneratorType {
    associatedtype Element
    public mutating func next() -> Self.Element?
}
protocol GeneratorType {
    associatedtype Element
    public mutating func next() -> Self.Element?
}
protocol CanPrint {
    
    associatedtype E
    
    func PrintType(output: E) -> Void
}
protocol CanPrint {
    
    associatedtype E
    
    func PrintType(output: E) -> Void
}

  听上去依旧有一定道理的,然后实行是查看事实的唯壹规范。下边我们经过代码实例来和C#拓展自己检查自纠。首先拿出网络多被引用解释上述八个意见的斯维夫特代码:

  听上去依旧有必然道理的,然后推行是验证事实的唯一标准。上面我们经过代码实例来和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()
    }
}
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()
    }
}
class TypePrinter0 : CanPrint{
    
    typealias E = String
    
    func PrintType(output: E) {
        print(type(of:output))
    }
}

let print0 = TypePrinter0()
print0.PrintType(output: "String Type")
class TypePrinter0 : CanPrint{
    
    typealias E = String
    
    func PrintType(output: E) {
        print(type(of:output))
    }
}

let print0 = TypePrinter0()
print0.PrintType(output: "String Type")

  具体的行使情状如下:

Swift泛型协议的N种用法。  具体的应用景况如下:

  然后就会在output窗口打字与印刷“String”。

  然后就会在output窗口打字与印刷“String”。

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

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

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

  阿西吧!这么意料之外的语法差不离不能够忍!就不能够用<Type>来写吗?

  阿西吧!这么出人意料的语法差不多不能够忍!就不可能用<Type>来写吗?

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

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

  曲线救国的话,我们得以思量模拟3个虚幻类class
CanPrintBase<T>,通过三番五次来完毕均等的功用:

  曲线救国的话,我们得以设想模拟3个虚幻类class
CanPrintBase<T>,通过持续来贯彻均等的功效:

    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();
        }
    }
    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();
        }
    }
class TypePrinter3: CanPrintBase<String>{
    
    override func PrintType(output: String){
         print(type(of:output))
    }
}

let print3 = TypePrinter3()
print3.PrintType(output: "String Type")
class TypePrinter3: CanPrintBase<String>{
    
    override func PrintType(output: String){
         print(type(of:output))
    }
}

let print3 = TypePrinter3()
print3.PrintType(output: "String Type")

  还足以依样画葫芦斯威夫特对Automobile多做1层承继实行打包:

  还可以够上行下效Swift对Automobile多做壹层承继举办李包裹装:

  那么大家像C#一致一向在类定义的时候经过占位符的章程得以嘛?

  那么大家像C#一样一向在类定义的时候经过占位符的点子能够嘛?

    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();
        }
    }
    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();
        }
    }
//This one cannot work!
class TypePrinter1<E: String> : CanPrint{
   
    func PrintType(output: E) {
        print(output)
    }
}
//This one cannot work!
class TypePrinter1<E: String> : CanPrint{
   
    func PrintType(output: E) {
        print(output)
    }
}

调用的时候从不什么样太大的差别:

调用的时候从不怎么太大的差别:

  错误提示为:Inheritance from non-protocol,
non-class type ‘String’。也便是说假如是class类型的话就足以:

  错误提醒为:Inheritance from non-protocol,
non-class type ‘String’。也正是说要是是class类型的话就能够:

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

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

  var simpleCar = new SimpleCar();
  simpleCar.Drive(gaso).Emit();
public class SomeType {}

class TypePrinter2<E: SomeType> : CanPrint{

    func PrintType(output: E) {
        print(output)
    }

}

let print2 = TypePrinter2()
print2.PrintType(output: SomeType())
public class SomeType {}

class TypePrinter2<E: SomeType> : CanPrint{

    func PrintType(output: E) {
        print(output)
    }

}

let print2 = TypePrinter2()
print2.PrintType(output: SomeType())

  和Swift相比差异的是,大家在Interface就代入了泛型参数。可是由于大家不能够向来实例化Interface,所以并无法一贯行使Automobile来缩短1层承接关系。

  和Swift相比分歧的是,大家在Interface就代入了泛型参数。可是由于大家无法一向实例化Interface,所以并无法直接使用Automobile来减弱壹层承继关系。

  反之大家也足以写成这么:

  反之大家也足以写成那样:

  因为上述提到的选取associatedtype 的首先点理由见仁见智,那里不分高下。

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

class TypePrinter5 : CanPrint{
    
    typealias E = SomeType
    
    func PrintType(output: E) {
        print(output)
    }
}

let print5 = TypePrinter5();
print(type(of: print5))
print(type(of: print2))
class TypePrinter5 : CanPrint{
    
    typealias E = SomeType
    
    func PrintType(output: E) {
        print(output)
    }
}

let print5 = TypePrinter5();
print(type(of: print5))
print(type(of: print2))

  C#还有第2种思路,便是自家也把泛型约束下放到Func层级:

  C#还有第两种思路,正是自作者也把泛型约束下放到Func层级:

  将品种打印出来的话,分别是TypePrinter五和TypePrinter贰<SomeType>,约等于说那二种写法获得的花色是全然不等同的。

  将项目打字与印刷出来的话,分别是TypePrinter5和TypePrinter二<SomeType>,也正是说那三种写法得到的品种是一点一滴不等同的。

    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>();
        }
    }
    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#的接口并不能够定义构造函数。强行模仿起来还真是有点累啊。最后的行使也很简短:

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

class TypePrinter4<E> : CanPrint{
    
    func PrintType(output: E) {
        print(output)
    }
}
let print4 = TypePrinter4<SomeType>()
print4.PrintType(output: SomeType())

let print6 = TypePrinter4<String>()
print6.PrintType(output: "I am a String")
class TypePrinter4<E> : CanPrint{
    
    func PrintType(output: E) {
        print(output)
    }
}
let print4 = TypePrinter4<SomeType>()
print4.PrintType(output: SomeType())

let print6 = TypePrinter4<String>()
print6.PrintType(output: "I am a String")
    var fuel = new UnleadedGasoline();
    var car2 = new Car2();
    car2.Drive<UnleadedGasoline,CleanExhaust>(fuel).Emit();
    var fuel = new UnleadedGasoline();
    var car2 = new Car2();
    car2.Drive<UnleadedGasoline,CleanExhaust>(fuel).Emit();

  这点又和C#傻傻分不清楚了。

  那一点又和C#傻傻分不清楚了。

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

  通篇相比下来,应该说斯威夫特通过associatedtype 关键字和<Type>的混用,使得泛型的定义更为复杂也越来越灵敏了。

  本篇实在是蛮无聊的纠缠与斯维夫特泛型协议的语法,如孔乙己般尝试了回字的N种写法。至于为啥斯威夫特要那样设计,我们下1篇能够品味和C#比较之下看看。

  本篇实在是蛮无聊的纠缠与Swift泛型协议的语法,如孔乙己般尝试了回字的N种写法。至于为啥斯维夫特要如此设计,我们下一篇能够品尝和C#相比较看看。

  GitHub:

  GitHub:

  GitHub:

  GitHub:

  

  

 

 

 

 

 

 

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有