Ios 从使用的泛型之一推断泛型类型

Ios 从使用的泛型之一推断泛型类型,ios,swift,generics,generic-programming,Ios,Swift,Generics,Generic Programming,我的应用程序中有一个非常复杂的结构,带有泛型类型。这是可行的,但有一个问题,在这个链的末尾,我需要指定一些类型2次,因为它们需要用作某个类的泛型,其中一个泛型类型也需要泛型类型。它们总是和以前的类型相同。它是这样的 这样使用起来有点不舒服。有什么方法可以让它从C 以下是示例代码,具有剥离的功能: // MARK: - Base classes that Im using, stripped from funcionalities. // This one is a base for perfo

我的应用程序中有一个非常复杂的结构,带有
泛型类型。这是可行的,但有一个问题,在这个链的末尾,我需要指定一些类型2次,因为它们需要用作某个类的泛型,其中一个泛型类型也需要泛型类型。它们总是和以前的类型相同。它是这样的

这样使用起来有点不舒服。有什么方法可以让它从
C
以下是示例代码,具有剥离的功能:

// MARK: - Base classes that Im using, stripped from funcionalities.

// This one is a base for performing some detection. It can return any type as a result of scanning.
class DetectionPerformer<ResultType> {}

// This one adds possibility to load some model needed to perform scanning from the disk.
class LocalFileDetectionPerformer<ResultType, LocalModelType>: DetectionPerformer<ResultType> {
    required init(localModelURL: URL) {}
}

// This one adds possibility to download this model and store it on the disk before loading.
class DownloadableDetectionPerformer<ResultType, LocalModelType>: LocalFileDetectionPerformer<ResultType, LocalModelType> {}

// This one wraps LocalFileDetectionPerformer inside DownloadableDetectionPerformer, and use them together.
class RemoteFileDetectionPerformer<ResultType, LocalModelType, LocalFileDetectionPerformerType: DownloadableDetectionPerformer<ResultType, LocalModelType>>: DetectionPerformer<ResultType> {
    
    private let localFileDetectionPerformer: LocalFileDetectionPerformerType
    
    init(remoteModelURL: URL) {
        let localModelURL = Self.localModelURL(for: remoteModelURL)
        localFileDetectionPerformer = LocalFileDetectionPerformerType(localModelURL: localModelURL)
    }
    
    static func localModelURL(for url: URL) -> URL {
        url.appendingPathExtension("local")
    }
}

// Detector is main object in application. It takes some type of Detector as init parameter, and works on it.
class Detector<ResultType, DetectionPerformerType: DetectionPerformer<ResultType>> {
    let performer: DetectionPerformerType

    init(performer: DetectionPerformerType) {
        self.performer = performer
    }
}

// Now I can implement some specific performers, whcich will do real work. For example:
class SamplePerformer: DownloadableDetectionPerformer<Int, String> {}

// And I'm able to create Detector with any type of Performer:

let detectorA = Detector(performer: SamplePerformer(localModelURL: URL(string: "")!))

// The problem begins, when I want to wrap Performer into RemoteFileDetectionPerformer

let detectorB = Detector(performer: RemoteFileDetectionPerformer<Int, String, SamplePerformer>(remoteModelURL: URL(string: "")!))

// Here I need to specify all 3 generic types of RemoteFileDetectionPerformer, even tough two first are always the same as generic types of SamplePerformer. I can't even specify different ones, as this would create an error.
// Is there some way for RemoteFileDetectionPerformer to infer these first two generic types from LocalFileDetectionPerformerType? Maybe I need to construct these some differently?
//标记:-我正在使用的基类,从函数性中剥离。
//这是执行某些检测的基础。作为扫描的结果,它可以返回任何类型。
类检测执行者{}
//这增加了从磁盘加载执行扫描所需的某些模型的可能性。
类LocalFileDetectionPerformer:DetectionPerformer{
必需的初始化(localModelURL:URL){}
}
//这增加了下载此模型并在加载前将其存储在磁盘上的可能性。
类DownloadableDetectionPerformer:LocalFileDetectionPerformer{}
//这一个将LocalFileDetectionPerformer包装在DownloadableDetectionPerformer中,并将它们一起使用。
类RemoteFileDetectionPerformer:DetectionPerformer{
私有let localFileDetectionPerformer:LocalFileDetectionPerformerType
初始化(remoteModelURL:URL){
让localModelURL=Self.localModelURL(for:remoteModelURL)
localFileDetectionPerformer=LocalFileDetectionPerformerType(localModelURL:localModelURL)
}
静态func localModelURL(用于url:url)->url{
url.appendingPathExtension(“本地”)
}
}
//探测器是应用的主要对象。它采用某种类型的检测器作为初始参数,并在其上工作。
类检测器{
让执行者:DetectionPerformerType
初始化(执行者:DetectionPerformerType){
self.performer=表演者
}
}
//现在我可以实现一些特定的执行者,而CICH将做真正的工作。例如:
类SamplePerformer:DownloadableDetectionPerformer{}
//我可以用任何类型的表演者创建探测器:
让detectorA=Detector(执行者:SamplePerformer(localModelURL:URL(字符串:“”)!)
//当我想将Performer包装到RemoteFileDetectionPerformer中时,问题就开始了
let detectorB=检测器(执行者:RemoteFileDetectionPerformer(remoteModelURL:URL(字符串:“”)!)
//在这里,我需要指定RemoteFileDetectionPerformer的所有3种通用类型,即使前两种类型始终与SamplePerformer的通用类型相同。我甚至不能指定不同的,因为这会产生错误。
//RemoteFileDetectionPerformer是否有办法从LocalFileDetectionPerformerType推断前两种泛型类型?也许我需要用不同的方式来构造这些?

我觉得在代码块的前半部分中显示的类应该是协议。也就是说,
DetectionPerformer
LocalFileDetectionPerformer
可下载的DetectionPerformer
都应该是协议。它们似乎没有任何真正的实现,正如您的评论“现在我可以实现一些特定的执行者,它们将做真正的工作”中所表明的那样。如果您有任何要放入其中的实现,那么大部分时间都可以将其放入扩展中。为什么让它们成为协议解决了这个问题?因为这样我们就可以使用关联的类型而不是类型参数

protocol DetectionPerformer {
    associatedtype ResultType
}

// This one adds possibility to load some model needed to perform scanning from the disk.
protocol LocalFileDetectionPerformer: DetectionPerformer {
    associatedtype LocalModelType
    init(localModelURL: URL)
}

// This one adds possibility to download this model and store it on the disk before loading.
protocol DownloadableDetectionPerformer: LocalFileDetectionPerformer {}

// This one wraps LocalFileDetectionPerformer inside DownloadableDetectionPerformer, and use them together.
class RemoteFileDetectionPerformer<LocalFileDetectionPerformerType: DownloadableDetectionPerformer>: DetectionPerformer {
    typealias ResultType = LocalFileDetectionPerformerType.ResultType
    private let localFileDetectionPerformer: LocalFileDetectionPerformerType
    
    init(remoteModelURL: URL) {
        let localModelURL = Self.localModelURL(for: remoteModelURL)
        localFileDetectionPerformer = LocalFileDetectionPerformerType(localModelURL: localModelURL)
    }
    
    static func localModelURL(for url: URL) -> URL {
        url.appendingPathExtension("local")
    }
}

class Detector<DetectionPerformerType: DetectionPerformer> {
    let performer: DetectionPerformerType

    init(performer: DetectionPerformerType) {
        self.performer = performer
    }
}

class SamplePerformer: DownloadableDetectionPerformer {
    required init(localModelURL: URL) {
        
    }
    
    typealias ResultType = Int
    typealias LocalModelType = String
}
协议检测执行者{
associatedtype结果类型
}
//这增加了从磁盘加载执行扫描所需的某些模型的可能性。
协议LocalFileDetectionPerformer:DetectionPerformer{
associatedtype LocalModelType
init(localModelURL:URL)
}
//这增加了下载此模型并在加载前将其存储在磁盘上的可能性。
协议DownloadableDetectionPerformer:LocalFileDetectionPerformer{}
//这一个将LocalFileDetectionPerformer包装在DownloadableDetectionPerformer中,并将它们一起使用。
类RemoteFileDetectionPerformer:DetectionPerformer{
typealias ResultType=LocalFileDetectionPerformerType.ResultType
私有let localFileDetectionPerformer:LocalFileDetectionPerformerType
初始化(remoteModelURL:URL){
让localModelURL=Self.localModelURL(for:remoteModelURL)
localFileDetectionPerformer=LocalFileDetectionPerformerType(localModelURL:localModelURL)
}
静态func localModelURL(用于url:url)->url{
url.appendingPathExtension(“本地”)
}
}
类检测器{
让执行者:DetectionPerformerType
初始化(执行者:DetectionPerformerType){
self.performer=表演者
}
}
类SamplePerformer:DownloadableDetectionPerformer{
必需的初始化(localModelURL:URL){
}
typealias ResultType=Int
typealias LocalModelType=字符串
}
这允许您执行以下操作:

let detectorB = Detector(performer: RemoteFileDetectionPerformer<SamplePerformer>(remoteModelURL: URL(string: "")!))
let detectorB=Detector(执行者:RemoteFileDetectionPerformer(remoteModelURL:URL(字符串:“”)!)

首先,我非常同意清扫者的观点。这几乎肯定是Swift中类继承和泛型的不当使用。通常,如果您认为需要类继承,那么应该首先使用其他工具。首先,组合(可以只传递函数或函数包)。然后是协议。查看您的类型,感觉您应该将“获取数据的东西”从“检测数据结果的东西”中分离出来,并将两者组合起来

这就是说,这个问题是普遍的、非常合理的,而且有一个解决办法。将类型作为参数传递:

init(performer: LocalFileDetectionPerformerType.Type, remoteModelURL: URL) { ... }
init(performer: LocalFileDetectionPerformerType.Type = LocalFileDetectionPerformerType.self, ...
然后,在调用它时,而不是显式地指定类型,传递类型:

let detectorB =
    Detector(performer: RemoteFileDetectionPerformer(performer: SamplePerformer.self,
                                                     remoteModelURL: URL(string: "https://example.com")!))
将自动计算出类型:

Detector<Int, RemoteFileDetectionPerformer<Int, String, SamplePerformer>>

然后,您可以在不需要参数时将其删除。

谢谢,您说得对,这是一个更好的设计。这些类确实有更多的功能