gpt4 book ai didi

swift - 如何快速组合多个类型删除模块?

转载 作者:搜寻专家 更新时间:2023-10-31 22:58:16 25 4
gpt4 key购买 nike

Swift 很棒但还不成熟,因此存在一些编译器限制,其中包括通用协议(protocol)。出于类型安全方面的考虑,通用协议(protocol)不能用作常规类型注释。我在 Hector Matos 的帖子中找到了解决方法。 Generic Protocols & Their Shortcomings

主要思想是使用类型删除将泛型协议(protocol)转换为泛型类,这很酷。但在将这项技术应用于更复杂的场景时,我遇到了困难。

假设有一个生成数据的抽象源,一个处理数据的抽象过程,以及一个将数据类型匹配的源和过程组合在一起的管道。

protocol Source {
associatedtype DataType
func newData() -> DataType
}
protocol Procedure {
associatedtype DataType
func process(data: DataType)
}
protocol Pipeline {
func exec() // The execution may differ
}

我希望客户端代码简单如下:

class Client {
private let pipeline: Pipeline
init(pipeline: Pipeline) {
self.pipeline = pipeline
}
func work() {
pipeline.exec()
}
}

// Assume there are two implementation of Source and Procedure,
// SourceImpl and ProcedureImpl, whose DataType are identical.
// And also an implementation of Pipeline -- PipelineImpl

Client(pipeline: PipelineImpl(source: SourceImpl(), procedure: ProcedureImpl())).work()

实现 Source 和 Procedure 很简单,因为它们位于依赖项的底部:

class SourceImpl: Source {
func newData() -> Int { return 1 }
}

class ProcedureImpl: Procedure {
func process(data: Int) { print(data) }
}

执行Pipeline时出现PITA

// A concrete Pipeline need to store the Source and Procedure, and they're generic protocols, so a type erasure is needed
class AnySource<T>: Source {
private let _newData: () -> T
required init<S: Source>(_ source: S) where S.DataType == T {
_newData = source.newData
}
func newData() -> T { return _newData() }
}
class AnyProcedure<T>: Procedure {
// Similar to above.
}

class PipelineImpl<T>: Pipeline {
private let source: AnySource<T>
private let procedure: AnySource<T>
required init<S: Source, P: Procedure>(source: S, procedure: P) where S.DataType == T, P.DataType == T {
self.source = AnySource(source)
self.procedure = AnyProcedure(procedure)
}
func exec() {
procedure.process(data: source.newData())
}
}

呃,实际上这个有效!我在跟你开玩笑吗?没有。

我对这个不满意,因为initializerPipelineImpl非常通用,所以我希望它出现在协议(protocol)中(我对这种痴迷有错吗?)。这导致了两端:

  1. 协议(protocol) Pipeline将是通用的。 initializer包含引用 placeholder T 的 where 子句,所以我需要移动 placeholder T作为 associated type 进入协议(protocol).然后协议(protocol)变成通用协议(protocol),这意味着我不能在我的客户端代码中直接使用它——可能需要另一种类型的删除。

    虽然我可以忍受为Pipeline写另一种类型删除的麻烦协议(protocol),我不知道如何处理 initializer function因为AnyPipeline<T>类必须实现关于协议(protocol)的初始化器,但它只是一个 thunk class实际上,它本身不应该实现任何初始化程序。

  2. 遵守协议(protocol)Pipeline非通用的。随着写作 initializer喜欢

    init<S: Source, P: Procedure>(source: S, procedure: P) 
    where S.DataType == P.DataType

    我可以防止协议(protocol)是通用的。这意味着该协议(protocol)仅声明“源和过程必须具有相同的数据类型,我不在乎它是什么”。这更有意义,但我未能实现确认此协议(protocol)的具体类

    class PipelineImpl<T>: Protocol {
    private let source: AnySource<T>
    private let procedure: AnyProcedure<T>
    init<S: Source, P: Procedure>(source: S, procedure: P)
    where S.DataType == P.DataType {
    self.source = AnySource(source) // doesn't compile, because S is nothing to do with T
    self.procedure = AnyProcedure(procedure) // doesn't compile as well
    }
    // If I add S.DataType == T, P.DataType == T condition to where clasue,
    // the initializer won't confirm to the protocol and the compiler will complain as well
    }

那么,我该如何处理呢?

感谢阅读allll这个。

最佳答案

我认为你有点过于复杂了(除非我遗漏了什么)——你的 PipelineImpl 看起来只不过是一个函数的包装器,它从Source 并将其传递给 Procedure

因此,它不需要是通用的,因为外界不需要知道传递的数据类型——它只需要知道它可以调用 exec()。因此,这也意味着(至少现在)您不需要 AnySourceAnyProcedure 类型的删除。

这个包装器的一个简单实现是:

struct PipelineImpl : Pipeline {

private let _exec : () -> Void

init<S : Source, P : Procedure>(source: S, procedure: P) where S.DataType == P.DataType {
_exec = { procedure.process(data: source.newData()) }
}

func exec() {
// do pre-work here (if any)
_exec()
// do post-work here (if any)
}
}

这让您可以自由地将初始化器添加到您的 Pipeline 协议(protocol)中,因为它不需要关心实际的 DataType 是什么——只需要源和过程必须具有相同的 DataType:

protocol Pipeline {
init<S : Source, P : Procedure>(source: S, procedure: P) where S.DataType == P.DataType
func exec() // The execution may differ
}

关于swift - 如何快速组合多个类型删除模块?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41376271/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com