Swift Generics/不透明类型:尝试使用协议一致性在通用函数中的类型之间转换

发布于 2025-02-10 06:41:20 字数 2409 浏览 3 评论 0原文

我正在构建一个转换器将我的dataObject s转换为modelObject s,反之亦然。我目前有两个函数可以进行转换。每个转换一个。

当前,我的两个转换函数都做得完全相同,而类型及其返回类型的例外。我希望我可以编写一个能够处理这两种转换的通用函数,因为否则,代码是完全相同的。

这是我所拥有的: 显然这些简化示例

我已经建立了一个协议,其中包含属性的要求和init()。我已经在dataObjectmodelObject中实现了此协议及其init()

我的协议

protocol MyProtocol {
    var id: UUID { get }
    var name: String? { get }

    init(id: UUID, name: String?)
}

我的dataObject

class DataObject: Object, MyProtocol {
    @Persisted(primaryKey: true) var id: UUID

    @Persisted var name: String?

    required convenience init(id: UUID, name: String?) {
        self.init()
        self.id = id
        self.name = name
    }
}

我的mode> mode> modebignt

struct ModelObject: MyProtocol {
    var id: UUID
    var name: String?

    init(id: UUID, name: String?) {
        self.id = id
        self.name = name
    }
}

当前: 这是当前正在进行转换的示例。我每个转换都有这样的一个。

static func buildModelObject(object: DataObject) -> ModelObject {
    let returnObject = ModelObject(id: object.id, name: object.name)
    return returnObject
}

所需的转换器函数: 我希望完成这样的事情。

static func buildObject<O: MyProtocol, R: MyProtocol>(objectIn: O, returnType: R.Type) -> R {
    let returnObject = returnType.init(id: objectIn.id, name: objectIn.name)
    return returnObject
}

和我称其为这样:

let object = Converter.buildObject(objectIn: dataObject, returnType: ModelObject.self)

显然,这是不起作用的。 错误: “协议'myprotocol'作为一种类型不能符合协议本身”。错误是在函数调用上。这是XCode在编译处向我显示的唯一错误。

我不确定在这里该怎么办或如何使其正常工作。我什至不相信此错误消息甚至以任何方式有所帮助。

问题:

甚至有可能完成这样的事情吗?如果是这样,我想念什么?我仍然对Swift Generics非常熟悉。

我没有使用多个转换函数的问题,因为它仍然比让整个代码库与领域特定的东西陷入困境要好。但是,鉴于这些功能本质上是相同的,我希望仿制药可以帮助将其他类似的代码减少到单个功能中。

注意: dataObject是一个领域对象。我知道它们具有诸如实时/托管对象之类的很酷的功能。我们正在尝试使用单个API/入口点使我们的持久性层与应用程序的其余部分完全分开。这就是为什么我使用这些转换器的原因。

I'm building a Converter to convert my DataObjects to ModelObjects and vice versa. I currently have two functions to do the converting. One for each conversion.

Currently, both of my conversion functions do exactly the same thing with exceptions to the type it takes and the type it returns. I was hoping I could write a generic function that would be able to handle both conversions because, otherwise, the code is exactly the same.

Here's what I've got: Obviously these are simplified examples

I've built a Protocol that contains the requirements for properties and an init(). I've implemented this Protocol and its init() in both the DataObject and ModelObject.

My Protocol:

protocol MyProtocol {
    var id: UUID { get }
    var name: String? { get }

    init(id: UUID, name: String?)
}

My DataObject:

class DataObject: Object, MyProtocol {
    @Persisted(primaryKey: true) var id: UUID

    @Persisted var name: String?

    required convenience init(id: UUID, name: String?) {
        self.init()
        self.id = id
        self.name = name
    }
}

My ModelObject:

struct ModelObject: MyProtocol {
    var id: UUID
    var name: String?

    init(id: UUID, name: String?) {
        self.id = id
        self.name = name
    }
}

Currently: This is an example what is currently doing the conversions. I have one like this for each conversion.

static func buildModelObject(object: DataObject) -> ModelObject {
    let returnObject = ModelObject(id: object.id, name: object.name)
    return returnObject
}

Desired Converter Function: I hope to accomplish something like this.

static func buildObject<O: MyProtocol, R: MyProtocol>(objectIn: O, returnType: R.Type) -> R {
    let returnObject = returnType.init(id: objectIn.id, name: objectIn.name)
    return returnObject
}

And I'm calling it like this:

let object = Converter.buildObject(objectIn: dataObject, returnType: ModelObject.self)

Obviously, this isn't working. Error: "Protocol 'MyProtocol' as a type cannot conform to the protocol itself". The error is on the function call. This is the only error XCode is showing me at compile.

I'm not certain what to do here or how to get it working. I'm not even confident that this error message is even helpful in any way.

The Question:

Is it even possible to accomplish something like this? If so, what am I missing? I'm still very unfamiliar with Swift Generics.

I don't have an issue with using multiple conversion functions as it's still better than getting the entire code base bogged down with Realm specific stuff. But, given that these functions are essentially the same, I'm hoping that Generics might be able to help reduce otherwise similar code into a single function.

Note: The DataObject is a Realm Object. I understand they have cool features like live/managed Objects. We're trying to keep our Persistence layer completely separated from the rest of the app with a single API/Entry Point. This is why I'm using these Converters.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

还在原地等你 2025-02-17 06:41:20

您几乎拥有它的

func buildObject<R: MyProtocol>(objectIn: MyProtocol, returnType: R.Type) -> R {
    let returnObject = returnType.init(id: objectIn.id, name: objectIn.name)
    return returnObject
}

关键观察:在任何时候我们都需要objectin的具体类型,因此只需要协议类型即可。

You almost had it

func buildObject<R: MyProtocol>(objectIn: MyProtocol, returnType: R.Type) -> R {
    let returnObject = returnType.init(id: objectIn.id, name: objectIn.name)
    return returnObject
}

the key observation: at no point do we need the concrete type of objectIn, so just require the protocol type.

各空 2025-02-17 06:41:20

您不需要其他论点。返回类型已经提供了类型信息。

func buildObject<R: MyProtocol>(objectIn: some MyProtocol) -> R {
  .init(id: objectIn.id, name: objectIn.name)
}

如评论中所建议的,这更惯用地表示为初始化器。

extension MyProtocol {
  init(_ objectIn: some MyProtocol) {
    self.init(id: objectIn.id, name: objectIn.name)
  }
}

You don't need the other argument. The return type already provides the type information.

func buildObject<R: MyProtocol>(objectIn: some MyProtocol) -> R {
  .init(id: objectIn.id, name: objectIn.name)
}

As suggested in the comments, this is more idiomatically expressed as an initializer.

extension MyProtocol {
  init(_ objectIn: some MyProtocol) {
    self.init(id: objectIn.id, name: objectIn.name)
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文