如何在Swift中使用相同类型在另一个泛型内部初始化一个泛型?

时间:2019-07-01 18:54:18

标签: swift generics

我正在尝试在另一个通用结构中使用通用结构。

public protocol FloatConvertible {
    init(_ other:Float)
    init(_ other:Double)
    init(_ x:FloatConvertible)

    func _asOther<T:FloatConvertible>() -> T
}

extension FloatConvertible {
    public init(_ x:FloatConvertible) {self = x._asOther()}
}
extension Float : FloatConvertible {
    public func _asOther<T:FloatConvertible>() -> T {return T(self)}
}

extension Double : FloatConvertible {
    public func _asOther<T:FloatConvertible>() -> T {return T(self)}
}

struct B<U> {
    var multVar: U
    init(multVar: U) {
        self.multVar = multVar
    }
}

struct A<T> {
    var array = [B<T>]()
    init(_ a: [T]) {
        for f in a {
            array.append(B<T>(multVar: f))
        }
    }
    func printResult(){
      var result: Float = 1.0
      for x in array {
          result = result * Float(x.multVar)
      }
    }

}

var array = [3.0,2.0]
var structA = A<FloatConvertible>(array)
structA.printResult()
generics.swift:37:29: error: initializer 'init(_:)' requires that 'T' conform to 'BinaryInteger'
          result = result * Float(x.multVar)
                            ^
Swift.Float:3:23: note: where 'Source' = 'T'
    @inlinable public init<Source>(_ value: Source) where Source : BinaryInteger

我收到此错误。

但是当我使用单个变量而不是数组时,将其类型强制转换为Float并打印出来,就可以了。

这是使用相同类型在另一个泛型结构中初始化泛型结构的正确方法吗?如果没有,我该怎么办?

我正在使用的实际代码如下:

// struct defining a data series
public struct Series<T,U> {
    public var barGraphSeriesOptions = BarGraphSeriesOptions()
    public var scatterPlotSeriesOptions = ScatterPlotSeriesOptions()
    public var pairs = [Pair<T,U>]()
    public var scaledPairs = [Pair<T,U>]()
    public var maxY: Float = 0
    public var minY: Float = 0
    public var label = "Plot"
    public var color : Color = .blue
    public var startColor: Color? = nil
    public var endColor: Color? = nil
    public init() {}

    public init(pairs : [Pair<T,U>], label l: String, startColor : Color = .lightBlue, endColor : Color = Color.lightBlue, hatchPattern: BarGraphSeriesOptions.Hatching = .none, scatterPattern: ScatterPlotSeriesOptions.ScatterPattern = .circle){
        self.pairs = pairs
        label = l
        self.startColor = startColor
        self.endColor = endColor
        barGraphSeriesOptions.hatchPattern = hatchPattern
        scatterPlotSeriesOptions.scatterPattern = scatterPattern
    }
    public init(pairs : [Pair<T,U>], label l: String, color c: Color = Color.lightBlue, hatchPattern: BarGraphSeriesOptions.Hatching = .none, scatterPattern: ScatterPlotSeriesOptions.ScatterPattern = .circle){
        self.pairs = pairs
        label = l
        color = c
        barGraphSeriesOptions.hatchPattern = hatchPattern
        scatterPlotSeriesOptions.scatterPattern = scatterPattern
    }
}

1 个答案:

答案 0 :(得分:0)

错误来自以下事实:在实现A<T>时,您的通用参数没有约束,这意味着它可能是任何(来自Float,到自定义结构/类)。

这意味着您不能将其转换为Float。例如,如果我使用自定义结构创建A的实例,则无法进行浮点转换。

struct A<T> {
    var array = [B<T>]()

    init(_ a: [T]) {
        for f in a {
            array.append(B<T>(multVar: f))
        }
    }
}

struct User {}
A([User(), User()]) // this is a valid initialization

但是在这一点上,您不能只将User投射到Float

Float(User()) // error

您可以通过以下方式解决此问题:

  • 在通用参数(在A结构中)添加约束
  • printResult()符合T时限制FloatConvertible方法的实现

约束A<T>

struct A<T: FloatConvertible> {
    var array = [B<T>]()

    init(_ a: [T]) {
        for f in a {
            array.append(B<T>(multVar: f))
        }
    }

    func printResult() {
        var result: Float = 1.0
        for x in array {
            result = result * Float(x.multVar)
        }
    }
}

var array = [3.0, 2.0]
var structA = A(array)
structA.printResult()

约束printResult()

struct A<T: FloatConvertible> {
    var array = [B<T>]()

    init(_ a: [T]) {
        for f in a {
            array.append(B<T>(multVar: f))
        }
    }
}

extension A where T: FloatConvertible {
    func printResult() {
        var result: Float = 1.0
        for x in array {
            result = result * Float(x.multVar)
        }
    }
}

var array = [3.0, 2.0]
var structA = A(array)
structA.printResult()