【问题标题】:How do I use Generics in a function call using Measurements in Swift 3如何在 Swift 3 中使用 Measurements 在函数调用中使用泛型
【发布时间】:2016-11-27 20:08:36
【问题描述】:

我需要一个可以处理 Swift 3 中任何测量值的函数。下面是一个示例:

var test2 = Measurement<UnitEnergy>( value: 10.1234, unit: .calories)

func printMeasurementGeneric( measurement: Measurement<Unit>) {
    print( measurement.value)
}

func printMeasurementEnergy( measurement: Measurement<UnitEnergy>) {
    print( measurement.value)
}

printMeasurementEnergy(measurement: test2) // This works
printMeasurementGeneric(measurement: test2)  // This doesn't work and give the following error

Playground execution failed: error: Measurement Playground.playground:136:38: error: cannot convert value of type 'Measurement<UnitEnergy>' to expected argument type 'Measurement<Unit>'
printMeasurementGeneric(measurement: test2)

PrintMeasurementGeneric 需要什么样的函数才能正常工作?

我已经取得了一些进展,现在在 Swift Playground 中有以下代码

var test = Measurement<UnitEnergy>( value: 10.1234, unit: .calories)

func printMeasurementGeneric<A:Dimension>( measurement: Measurement<A>) {
    print( measurement.value)
}

// This works
printMeasurementGeneric(measurement: test) // This works

// The following doesn't work
var objectValue: Any?
objectValue = test

var meas = objectValue as! Measurement<Dimension> // Could not cast value of type 'Foundation.Measurement<NSUnitEnergy>' (0x11d324028) to 'Foundation.Measurement<NSDimension>' (0x11d324088).
printMeasurementGeneric(measurement: meas)

我正在尝试使用 NSControl 中的 objectValue 来保存测量值。在检查是否可以将其转换为每种测量类型时如何执行此操作?

还有一些工作,包括下面的编辑。不是一个漂亮或强大的解决方案。

var test = Measurement<UnitEnergy>( value: 10.1234, unit: .calories)

func printMeasurementGeneric<A>( measurement: Measurement<A>) {
    print( measurement.value)
}

// This works
printMeasurementGeneric(measurement: test) // This works

// The following works but isn't pretty. Is there a better way
var objectValue: Any?
objectValue = test

if objectValue is Measurement<UnitFrequency> {
    let meas = objectValue as! Measurement<UnitFrequency>
    printMeasurementGeneric(measurement: meas)
} else if objectValue is Measurement<UnitLength> {
    let meas = objectValue as! Measurement<UnitLength>
    printMeasurementGeneric(measurement: meas)
} else if objectValue is Measurement<UnitSpeed> {
    let meas = objectValue as! Measurement<UnitSpeed>
    printMeasurementGeneric(measurement: meas)
}  else if objectValue is Measurement<UnitEnergy> {
    let meas = objectValue as! Measurement<UnitEnergy>
    printMeasurementGeneric(measurement: meas)
} else {
    print("Didn't find cast!")
}

【问题讨论】:

  • 第一步是停止这种以大写字母开头的函数名的做法。停下来吧。现在。谢谢。
  • 修正了大写。从 objectValue 中获取测量值的第 2 步是 NSControl?

标签: swift generics swift3


【解决方案1】:

将您的 PrintMeasurementGeneric 函数更改为此。

func PrintMeasurementGeneric<Dimension>( measurement: Measurement<Dimension>) {
  print( measurement.value)
}

我使用了Dimension 类型而不是Unit。两者都可以,但所有测量类型都符合DimensionUnit 的抽象子类)。

Hamish(下)是对的。

【讨论】:

  • 我认为这里有点混乱——说&lt;Dimension&gt;引入了一个新的通用占位符Dimension,但与FoundationDimension类完全无关——你可以去提前打电话给通用占位符FooBar,它不会有什么不同。另外,您说“DimensionUnit 是协议”是不正确的——它们实际上是类。强制转换不起作用的原因是泛型是不变的。
【解决方案2】:

这可以通过协议来完成:

protocol HasValue {
    var value: Double { get set }
}
extension Measurement: HasValue { }

func printValue<T: HasValue>(of item: T) {
    print(item.value) // prints "10.1234"
}


var test = Measurement<UnitEnergy>( value: 10.1234, unit: .calories)
printValue(of: test)

任何类似于 printValue 的函数都应该能够通用地使用任何度量。您可以在组织的协议扩展中包含这些功能。

【讨论】:

    猜你喜欢
    • 2017-06-07
    • 1970-01-01
    • 2020-06-17
    • 1970-01-01
    • 2019-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多