简体   繁体   中英

Swift Generic Protocol Function Parameters

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
    }
}

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
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM