指定通用值参数作为对象初始化调用的参数

时间:2019-01-18 19:37:52

标签: swift generics

我有一个结构Event,该结构用时间和值初始化。

value属性的类型是在创建事件时确定的。它可以是IntDouble原语之一。

我应该如何在Swift中实现呢?

我希望能够像这样创建一个新的Event对象:

let event = Event(time: Date.init(), value: EventValue<Double>(40.3467)) 

我找到了this,但我听不清。

我已经尝试了很多这样的排列,而我能做的最好的是

struct Event {
  let time: Date
  var value: EventValue? // This line 'requires arguments in <...>'
}

struct EventValue <T> {
  let value: T?
}

4 个答案:

答案 0 :(得分:4)

由于EventValue是通用属性,因此不能直接用作属性的类型。*您必须直接指定type参数,这将为您提供一个容器,该容器始终具有特定的{ {1}}:

EventValue

或者也使容器通用:

struct DoubleEvent {    // Please pick a better name, though
    let time: Date
    var value: EventValue<Double>?
}

在任何一种情况下,创建struct Event<T> { let time: Date var value: EventValue<T>? } 时都不必显式给出类型:Eventlet event = Event(time: Date(), value: EventValue(value: 40.3467))本身是泛型的情况下将使用类型推断进行填充。

(此外:请注意,您没有正式限制Event只能是TDouble。例如,Int也可以。如果您这样做,希望严格避免这种情况,Martin R's answer gives one solution。)


*无需过多讨论,它更像是“创建类型的事物”,而不是类型本身。

答案 1 :(得分:3)

也将通用参数添加到您的Event结构中,然后将此类型用于EventValue的参数

struct Event<T> {
    let time: Date
    var value: EventValue<T>?
}

然后只初始化EventValue而不指定类型,因为编译器允许您只传递与通用参数约束相对应的值。而且由于您的参数没有约束,所以它等于Any,因此您可以传递任何类型

let event = Event(time: Date.init(), value: EventValue(value: 40.3467))

答案 2 :(得分:2)

如果要使用Event属性的(单个)EventValue类型,该属性可以容纳 一个整数一个double值,那么具有关联值的enum可以达到目的:

enum EventValue {
    case ival(Int)
    case dval(Double)
}

struct Event {
    let time: Date
    let value: EventValue
}

let event1 = Event(time: Date(), value: .dval(40.3467))
let event2 = Event(time: Date(), value: .ival(1234))

答案 3 :(得分:0)

如果要在相同的EventValue类型下支持各种Event(即Event没有通用名称),则可以存储EventValue的协议参考:

protocol EventValueProtocol {
    var time: Date { get }
    var value: SomeCommonGroundProtocolOrClass
}

struct Event {
    let time: Date

    // note that the generics information is lost
    // when using the protocol
    var value: EventValueProtocol

    init<T>(time: Date, value: EventValue<T>) {
        self.time = time
        self.value = value
    }
}

struct EventValue <T>: EventValueProtocol {
    let value: T?
}

“类型擦除器”协议的缺点是,您松散了用于EventValue通用参数的类型信息,但是,也许可以通过一些辅助方法来解决此问题。协议。例如,您可以为所有T泛型参数使用一个公共分母,以访问该公共功能(除非您想切换T可以接受的所有可能类型,否则您确实需要这样做)。