Swift Generic Protocol Function Parameters

大兔子大兔子 提交于 2019-12-02 19:25:40

问题


This seems like it should work to me. All I am trying to do is make the Rule protocol able to performRule on whatever struct adopts that Rule protocol and then return a boolean. However, with the way my code is currently I cannot access any properties on the performRule(:value) value parameter. I feel like I am missing an important concept or something is buggy. You should be able to copy the code below into a playground to see the issue for yourself.

import Foundation

protocol NumberCalculation {
    var number : NSNumber { get set }
}

protocol Rule {
    var invalidMessage : String { get set }
    func performRule<T>(value: T) -> Bool
}

struct GreaterThanRule : Rule, NumberCalculation  {
    var invalidMessage: String
    var number : NSNumber

    init(valueMustBeGreaterThan value: NSNumber, withInvalidMessage message : String = "") {
        number = value
        invalidMessage = message
    }

    func performRule<NSNumber>(value: NSNumber) -> Bool {
        number.decimalValue // works 
        value.decimalValue // doesn't work
        return true
    }
}

回答1:


Saying <NSNumber> defines a new generic placeholder type in your performRule(value:) method, which, as you've named it NSNumber, will shadow Foundation's NSNumber class – meaning that the value: parameter is of type your generic placeholder, not Foundation's NSNumber.

If you want it so that types conforming to Rule can choose their own type for the parameter of the performRule(value:) method – then you want an associated type, not a generic placeholder.

protocol NumberCalculation {
    var number : NSNumber { get set }
}

protocol Rule {

    // define associated type that conforming types must satisfy
    // by providing a type to replace it with
    associatedtype Value
    var invalidMessage : String { get set }
    func performRule(value: Value) -> Bool
}

struct GreaterThanRule : Rule, NumberCalculation {

    var invalidMessage: String
    var number : NSNumber

    init(valueMustBeGreaterThan value: NSNumber, withInvalidMessage message : String = "") {
        number = value
        invalidMessage = message
    }

    // satisfy associated type implicitly by annotating the type of the parameter
    // as NSNumber – the compiler will infer that Value == NSNumber.
    func performRule(value: NSNumber) -> Bool {
        number.decimalValue // works
        value.decimalValue // also works!
        return true
    }
}


来源:https://stackoverflow.com/questions/40442497/swift-generic-protocol-function-parameters

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!