使用符合协议的 class 作为参数创建 class 的新实例

Creating a new instance of a class with a protocol-conforming class as an argument

我有以下代码设置(写在Swift):

protocol DataFetcherType {
    init(_ mainData: String, fetchData: Bool)
}

class DataFetcher1: DataFetcherType {
    required init(_ mainData: String, fetchData: Bool) {
    }
}

class DataFetcher2: DataFetcherType {
    required init(_ mainData: String, fetchData: Bool) {
    }
}

struct Data<FetcherType: DataFetcherType> {
    var mainData: String
    var fetcher: DataFetcherType
    
    init(_ mainData: String, using fetcher: FetcherType, fetchData: Bool = true) {
        self.mainData = mainData
        self.fetcher = FetcherType(mainData, fetchData: fetchData)
    }
}

我正在尝试像这样实例化 Data

Data("foo", using: DataFetcher1)

但我收到错误消息:

Type 'DataFetcher1.Type' cannot conform to 'DataFetcherType'

DataFetcher2试试也是一样。

我已经用了几个小时了,我觉得我已经改变了所有可能的东西,但我就是无法让它工作。我最初的尝试没有使用泛型,但我最终决定这可能是我需要做的。那是错的,还是我从根本上遗漏了一些关于 Swift 是如何工作的东西?

你必须通过参数取一个类型而不是一个对象。

将您的数据结构初始化程序重写为:

struct Data<FetcherType: DataFetcherType> {
    var mainData: String
    var fetcher: DataFetcherType
    
    init(_ mainData: String, using fetcher: FetcherType.Type, fetchData: Bool = true) {
        self.mainData = mainData
        self.fetcher = FetcherType(mainData, fetchData: fetchData)
    }
}

let data = Data("Data fetcher1", using: DataFetcher2.self)
print(data.fetcher)

您根本不需要传递任何类型。 using 参数完全没有必要。删除它。这是一个通用的;传递类型会使泛型变得毫无意义!

声明要实例化的内容时,只需解析泛型即可。 (并且不要称某些数据为数据,该名称已被使用。)

所以,如果我们从这个开始:

protocol DataFetcherType {
    init(_ mainData: String, fetchData: Bool)
}
class DataFetcher1: DataFetcherType {
    required init(_ mainData: String, fetchData: Bool) {
    }
}
class DataFetcher2: DataFetcherType {
    required init(_ mainData: String, fetchData: Bool) {
    }
}

...那么这就是您所需要的:

struct MyData<FetcherType: DataFetcherType> {
    var mainData: String
    var fetcher: FetcherType
    init(_ mainData: String, fetchData: Bool = true) {
        self.mainData = mainData
        self.fetcher = FetcherType.init(mainData, fetchData: fetchData)
    }
}

...因为要制作一个,您只需解析类型即可:

    let mydata = MyData<DataFetcher1>("hey")

此外,请注意我已经更改了变量的类型 fetcher。应该是泛型,不是协议.

一般来说,如果您发现自己在 Swift 中传递类型,那是一种难闻的气味,您应该重新考虑。可以做,有时也做,但总的来说Swift不喜欢metatypes,应该避免。

协议也是如此;如果你发现你正在输入一些东西作为协议,请重新考虑。

这正是泛型存在的原因,因此您不要做那些事情。