依赖注入一个通用结构,而不必重新指定占位符类型或约束

时间:2016-11-19 13:07:57

标签: ios swift xcode generics

我正在尝试依赖注入一个通用结构到类中,但我不想在类中再次重新指定泛型的占位符类型。由于任何使用此类的类都必须执行相同的操作,因此失控。

例如,这有效:

struct SomeStruct<T : CustomStringConvertible> {
    let data: T
}

class SomeClass {
    let someStruct = SomeStruct(data: 1)
}

但是,如果我想将struct依赖注入class,我会收到错误:

struct SomeStruct<T : CustomStringConvertible> {
    let data: T
}

class SomeClass {
    let someStruct: SomeStruct
    //              ^
    // Reference to generic type 'SomeStruct' requires arguments in <...>

    init(someStruct: SomeStruct) {
    //               ^
    // Reference to generic type 'SomeStruct' requires arguments in <...>
        self.someStruct = someStruct
    }
}

那么我必须在class

中再次指定占位符类型和类型约束
struct SomeStruct<T : CustomStringConvertible> {
    let data: T
}

class SomeClass<T : CustomStringConvertible> {
    let someStruct: SomeStruct<T>

    init(someStruct: SomeStruct<T>) {
        self.someStruct = someStruct
    }
}

有没有办法解决在类中重新指定占位符类型和约束的问题?为什么班级不能知道SomeStruct持有data: CustomStringConvertible

2 个答案:

答案 0 :(得分:1)

不,这是不可能的。您试图描述一个允许指定具体(class)类型的概念:

class SomeClass { ... }

但使用非具体类型作为成员

class SomeClass { 
    let someStruct: SomeStruct // <-- non-specified generic type, what placeholder should we use?
}

对于任何具体类型,其成员也必须具体

// OK
class SomeClass { 
    let someStruct: SomeStruct<Int>
}

然而,如果通用成员的类型与拥有类型(SomeClass)本身的通用类型持有者相关联,则可以允许通用成员

// OK (assuming there is no type constraint on the
//     generic placeholder in the definition of SomeStruct)
class SomeClass<T> {
    let someStruct: SomeStruct<T>
}

最后,关于“重复”类型约束:如果某个给定类型的通用占位符(如问题中的SomeStruct<T>)在某种类型约束下,那么自然(静态类型)任何类型持有者“传播“必须确保通用SomeStruct的用法中的泛型类型说明符符合与SomeStruct中应用于通用占位符的约束相同的约束。因此,您无法避免在通用类SomeClass<T: ...>中指定相同的类型约束,SomeStruct被用作一般关联成员。

struct SomeStruct<T : CustomStringConvertible> {
    let data: T
}

class SomeClass<T> {
    let someStruct: SomeStruct<T>
                            /* ^ this placeholder is not guaranteed to fulfil
                                 the type constraints which are applied to the
                                 generic typeholder of SomeStruct, hence the
                                 illegality */
}

答案 1 :(得分:0)

CustomStringConvertible不是具体类型。编译器无法推断出基本类型(符合CustomStringConvertible)的真实含义。

对于这种特定情况,如果SomeClass所需的唯一功能someStruct能够以data的身份访问String,那么您应该只需转换注入的类型(比如someStruct)首先进入字符串。