如何为仅适用于 Swift 4.1 中的可选泛型参数的泛型结构创建扩展?

How to create extension for a generic structure that will be available only for Optional generic parameters in Swift 4.1?

我的 iOS 应用程序中有以下结构:

struct MyStruct<T> {

    var property1: T
    var property2: T

    init(property1: T, property2: T) {
        self.property1 = property1
        self.property2 = property2
    }

    init(allPropertiesWith value: T) {
        self.property1 = value
        self.property2 = value
    }
}

我也有 2 个 类 没有共同的祖先:

class A { }
class B { }

在我的应用程序中,我有 MyStruct<A>MyStruct<B>MyStruct<A?>MyStruct<B?> 的实例,我在这些函数中使用它们:

func f1(myStrurct: MyStruct<A?>) { }

func f2(myStrurct: MyStruct<A>) { }

func g2() {
    f1(myStrurct: MyStruct<A?>(property2: A()))
} 
/* I also have the same functions for MyStruct<B> and MyStruct<B?> */

我无法修改 f1f2g2。这就是为什么我创建了 2 个扩展来简化 MyStruct<T> 的初始化:

extension MyStruct where T == A? {

    init(property1: T) {
        self.property1 = property1
        self.property2 = nil
    }

    init(property2: T) {
        self.property1 = nil
        self.property2 = property2
    }
}

extension MyStruct where T == B? {

    init(property1: T) {
        self.property1 = property1
        self.property2 = nil
    }

    init(property2: T) {
        self.property1 = nil
        self.property2 = property2
    }
}

如您所见,这些扩展名几乎相同。是否可以只用 1 个扩展来重构它?

您可以使 AB(或任何 class 需要它)都符合 虚拟协议 并检查是否T.

protocol MyStructProtocol {

}

class A: MyStructProtocol { }
class B: MyStructProtocol { }

extension MyStruct where T == MyStructProtocol? {
    init(property1: T) {
        self.property1 = property1
        self.property2 = nil
    }

    init(property2: T) {
        self.property1 = nil
        self.property2 = property2
    }
}

您无需扩展任何内容即可创建如此简单的构造函数。在下面查看结构定义的修改版本:

struct MyStruct<T> {

    var property1: T?
    var property2: T?

    init(property1: T? = nil, property2: T? = nil) {
        if T.self == String.self {
            self.property1 = property1
            self.property2 = nil
        }
        else if T.self == Int.self {
            self.property1 = nil
            self.property2 = property2
        }
    }

    init(allPropertiesWith value: T) {
        self.property1 = value
        self.property2 = value
    }
}

然后您可以根据需要使用以下几行初始化它们。

MyStruct<String>(property2: "sadsad")
MyStruct<Int>(property1: 23)

provided by Rakesha Shastri 中我发现我可以使用 protocol 来重构我的代码。但是,为了能够使用此解决方案,我需要重写应用程序的其他部分。我尝试将 Rakesha Shastri 的解决方案添加到我的应用程序中,并使用 Swift 3、Swift 4 或 Swift 4.2(所有 Swift 版本在 Xcode 10.0),但每次我都会收到编译错误。这意味着目前没有办法解决我在这个问题中描述的问题。