如何在方法参数中使用Rawtypes遵守协议方法?

protocol Measurement { mutating func convert(#toUnit: String) } enum MassUnit : String { case Milligram = "mg" } enum VolumeUnit : String { case Milliliter = "ml" } struct Mass : Measurement { mutating func convert(#toUnit: MassUnit) // Build error: Does not adhere to 'Measurement' } struct Volume : Measurement { mutating func convert(#toUnit: VolumeUnit) // Build error: Does not adhere to 'Measurement' } func +<T: Measurement> (left:T, right:T) -> Measurement { let newRightValue = right.convert(toUnit: left.unit) return T(quantity: left.quantity + newRightValue.quantity , unit: left.unit) } 

我如何让Mass能够正确地遵循Measurement ? 需要在Measurement协议中做什么改变才能使用Stringtypes的枚举?

问题更新了更多的信息,为什么转换方法签名应该说一些关于给出的论点。 这个代码是我正在build设的一个叫做Indus Valley的开源单元框架的一部分

在处理你的单位转换时,我build议不要在使用上面设置的方式转换时使用String来表示单位。 这将使你的代码变得复杂,检查String可以转换为各自的枚举,每次你想进行转换。 另外,如果你想使用一个MassUnit / VolumeUnit而不是一个String呢?

我会build议使用类似于我下面概述的设置。 它引用了我以前的答案 – 如何在Swift中表示质量的大小?

(注意 – 我已经排除了与音量有关的任何事情,因为它与质量的实现基本相同)

我会这样做的单位:

 protocol UnitProtocol { var magnitude: Int { get } init?(rawValue: String) } // Taken from my previous answer. enum MassUnit: String, UnitProtocol, Printable { case Milligram = "mg" case Gram = "g" var magnitude: Int { let mag: Int switch self { case .Milligram: mag = -3 case .Gram : mag = 0 } return mag } var description: String { return rawValue } } // Not making this a method requirement of `UnitProtocol` means you've only got to // write the code once, here, instead of in every enum that conforms to `UnitProtocol`. func ordersOfMagnitudeFrom<T: UnitProtocol>(unit1: T, to unit2: T) -> Int { return unit1.magnitude - unit2.magnitude } 

那么我会这样做群众/卷:

 protocol UnitConstruct { typealias UnitType: UnitProtocol var amount: Double { get } var unit : UnitType { get } init(amount: Double, unit: UnitType) } struct Mass : UnitConstruct { let amount: Double let unit : MassUnit } 

现在的转换function! 使用全局函数意味着您不需要重写每个types的代码,而不是符合UnitConstruct

 func convert<T: UnitConstruct>(lhs: T, toUnits unit: T.UnitType) -> T { let x = Double(ordersOfMagnitudeFrom(lhs.unit, to: unit)) return T(amount: lhs.amount * pow(10, x), unit: unit) } // This function is for converting to different units using a `String`, // as asked in the OP. func convert<T: UnitConstruct>(lhs: T, toUnits unit: String) -> T? { if let unit = T.UnitType(rawValue: unit) { return convert(lhs, toUnits: unit) } return nil } 

您可以使用之前的代码,如下所示:

 let mass1 = Mass(amount: 1.0, unit: .Gram) let mass2 = convert(mass1, toUnits: .Milligram) // 1000.0 mg // Or, converting using Strings: let right = convert(mass1, toUnits: "mg") // Optional(1000.0 mg) let wrong = convert(mass1, toUnits: "NotAUnit") // nil 

您可能会混淆enum MassUnit : String与inheritance。

class ChildClass : ParentClass表示ChildClassinheritance自ParentClass相反, enum MassUnit : String具有稍微不同的含义,告诉枚举的rawTypeString ,而不是枚举inheritanceStringtypes。

所以MassUnit不是Stringtypes的。 你的MassUnitrawValue是Stringtypes的,但是为了访问你需要调用enum的rawValue属性来获得这个String等价物。

因此, mutating func convert(#toUnit: String)mutating func convert(#toUnit: MassType)不兼容,因为MassType本身不是String 。 只有它的rawValue是。