如何使协议关联类型需要协议继承而不是协议采用

2023-11-23

在我的 swift 项目中,我有一个使用协议继承的情况,如下所示

protocol A : class{

}

protocol B : A{

}

接下来我想要实现的是声明另一个具有关联类型的协议,该类型必须从协议继承A。如果我尝试将其声明为:

protocol AnotherProtocol{
    associatedtype Type : A
    weak var type : Type?{get set}
}

它编译时没有错误,但是当尝试采用时AnotherProtocol在以下场景中:

class SomeClass : AnotherProtocol{

    typealias Type = B
    weak var type : Type?
}

编译失败并出现错误声明SomeClass不符合AnotherProtocol。如果我理解正确的话,这意味着B不采用A当我尝试声明并询问您如何声明从协议继承的关联类型时A?

我做出上述假设是基于以下场景编译得很好的事实

class SomeDummyClass : B{

}

class SomeClass : AnotherProtocol{

    typealias Type = SomeDummyClass
    weak var type : Type?
}

这很有趣。它appears一旦你限制了一个类型associatedtype在给定的协议中,您需要在该协议的实现中提供具体类型(而不是其他协议类型)——这就是第二个示例起作用的原因。

如果您删除A对关联类型的约束,您的第一个示例将起作用(减去有关无法使用的错误weak在非类类型上,但这似乎不相关)。

话虽这么说,我似乎找不到任何文档来证实这一点。如果有人能找到一些东西来支持这一点(或完全质疑它),我很想知道!

为了让当前的代码正常工作,您可以使用泛型。这实际上会一石二鸟,因为您的代码现在都将编译,并且您将受益于泛型带来的增强的类型安全性(通过推断您传递给它们的类型)。

例如:

protocol A : class {}
protocol B : A {}

protocol AnotherProtocol{
    associatedtype Type : A
    weak var type : Type? {get set}
}

class SomeClass<T:B> : AnotherProtocol {
    typealias Type = T
    weak var type : Type?
}

Edit:看来上述解决方案在您的特定情况下不起作用,因为您想避免使用具体类型。我会把它留在这里,以防对其他人有用。


根据您的具体情况,您may能够使用类型擦除来为您创建伪具体类型B协议。Rob Napier 有一篇很棒的文章关于类型擦除。

在这种情况下,这是一个有点奇怪的解决方案(因为类型擦除通常用于包装协议associatedtypes),而且它也绝对不如上面的解决方案,因为你必须为你的每个方法重新实现一个“代理”方法A & B协议——但它应该适合你。

例如:

protocol A:class {
    func doSomethingInA() -> String
}

protocol B : A {
    func doSomethingInB(foo:Int)
    func doSomethingElseInB(foo:Int)->Int
}

// a pseudo concrete type to wrap a class that conforms to B,
// by storing the methods that it implements.
class AnyB:B {

    // proxy method storage
    private let _doSomethingInA:(Void)->String
    private let _doSomethingInB:(Int)->Void
    private let _doSomethingElseInB:(Int)->Int

    // initialise proxy methods
    init<Base:B>(_ base:Base) {
        _doSomethingInA = base.doSomethingInA
        _doSomethingInB = base.doSomethingInB
        _doSomethingElseInB = base.doSomethingElseInB
    }

    // implement the proxy methods
    func doSomethingInA() -> String {return _doSomethingInA()}
    func doSomethingInB(foo: Int) {_doSomethingInB(foo)}
    func doSomethingElseInB(foo: Int) -> Int {return _doSomethingElseInB(foo)}
}

protocol AnotherProtocol{
    associatedtype Type:A
    weak var type : Type? {get set}
}

class SomeClass : AnotherProtocol {
    typealias Type = AnyB
    weak var type : Type?
}

class AType:B {
    // implement the methods here..
}
class AnotherType:B {
    // implement the methods here..
}

// your SomeClass instance
let c = SomeClass()

// set it to an AType instance
c.type = AnyB(AType())

// set it to an AnotherType instance
c.type = AnyB(AnotherType())

// call your methods like normal
c.type?.doSomethingInA()
c.type?.doSomethingInB(5)
c.type?.doSomethingElseInB(4)

您现在可以使用AnyB键入代替使用B协议类型,而不对其进行更多类型限制。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使协议关联类型需要协议继承而不是协议采用 的相关文章

随机推荐

  • 使用 Devise after_sign_in_path_for 重定向循环

    我有一个菜鸟问题 我想要设计重定向到用户访问的最后一个页面 所以我做了以下 def after sign in path for resource request referer end 效果很好 除非用户实际上通过原始表单登录 这会导致重
  • 在 C++ 中,通过引用扩展范围是否安全?

    在 C 中 通过引用扩展范围是否安全 在代码中 我的意思是 MyCLass function badIdea MyClass obj1 return obj1 通过引用扩展范围是不安全的 C 中的对象没有引用计数 当 obj1 超出范围时
  • XFL - ./bin/*.dat 文件是什么?

    未压缩的 Adob e Flash XFL 格式仍保留大量压缩内容 有人知道这些二进制 dat 文件的规范吗 dat 文件存储各种类型的媒体内容 到目前为止我能说的是 图像存储为 JPEG 没有附加信息 这意味着只需重命名 dat 就足以获
  • 创建自定义上传进度条

    我见过所有的上传进度条插件 小部件等 它们都很糟糕 它们要么体积太大 有太多无用的代码 要么不起作用 我想知道在哪里可以阅读如何显示简单的上传进度指示器 大多数浏览器下面都有一个状态进度条 但在与客户打交道时仅使用它不太专业 浏览器是如何做
  • Android手写识别[关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 我需要分析android手写识别SDK 谁能告诉我市场上有哪些 SDK 我发现了MyScript来自 VisionObjects 但我找不到 SDK 的任何下载链接 因为我需要测试以
  • 将数字格式设置为固定宽度,并带有前导零[重复]

    这个问题在这里已经有答案了 下面的代码 a lt seq 1 101 25 b lt paste name 1 length a sep 产生这个输出 name 1 name 26 name 51 name 76 name 101 我希望所
  • 使用参数包将 lambda 转换为 std::function

    SO 有几个问题与将 lambda 转换为std functions 但我还没有看到使用参数包作为参数列表的 这在我的 g 版本 7 1 1 4 上似乎被破坏了 并且可能只是不受支持 那么这是合法的 c 17 按照标准 吗 如果没有 为什么
  • 可扩展的内存分配器体验

    我目前正在评估一些可扩展的内存分配器 即 nedmalloc 和 ptmalloc 两者都构建在 dlmalloc 之上 作为默认 malloc new 的替代品 因为在多线程环境中出现了严重的争用 他们公开的表现似乎不错 但我想看看其他真
  • 如何在 Heroku 云上部署 Scrapy 蜘蛛

    我在 scrapy 中开发了一些蜘蛛 我想在 Heroku 云上测试它们 有人知道如何在 Heroku 云上部署 Scrapy 蜘蛛吗 是的 在 Heroku 上部署和运行 Scrapy 蜘蛛相当简单 以下是使用真实 Scrapy 项目作为
  • Wix Bootstrapper MSI-Package 日志记录,如何?

    我有一个安装了的引导程序MSI 包 我怎样才能至少记录 msi 软件包安装 详细记录 我在哪里可以设置日志文件路径 因为我无法记录我猜的所有内容 不 我don t want a cmd 解决方案 我需要实现这个进入我的设置 找到了 LogP
  • Maven:属性标签中pom.xml中的if语句

    如果设置了环境变量 我想设置一个属性 我在谷歌上搜索了很多 我发现的只是类似于下面的代码 但我不断收到错误 致命 不可解析的 POM Y Maven parent pom pom xml TEXT 后面必须紧跟 END TAG 而不是 ST
  • “new int(100)”有什么作用?

    可能的重复 这是变量还是函数 我错误地使用了类似的东西 int arr new int 100 它通过了编译 但我知道这是错误的 它应该是 int arr new int 100 当我写错了 编译器会认为是什么 第一行分配一个int并将其初
  • 在 flutter 中向特定用户 firebase 发送通知

    当一个用户按下按钮时 如何向另一个用户发送通知 有人可以给我看一个代码片段吗 我意识到这个问题之前曾被问过 但是 由于有 几个答案 所以它被关闭了 提供的类似链接并未解释在中发送通知flutter 我已经弄清楚如何使用应用程序内功能将通知发
  • Laravel Excel 可以工作,但文件无法打开

    我正在使用Laravel Excel创建包含多个工作表的 Excel 文档 我一直在遵循他们的示例 了解他们是如何做到这一点的 但是当我去下载文件时 它是 Excel 无法打开文件 kingdoms 1 xlsx 因为文件格式或文件扩展名无
  • 修复从 C# Azure Function 引用 System.Data.SqlClient 时出现的 PlatformNotSupportedException

    我正在使用 C 的目标框架创建 Azure 函数netstandard2 0在 Windows 10 环境中 该函数调用另一个类库中的方法 并且该方法创建 SqlConnection 的实例 当我运行该函数时 出现以下异常 Microsof
  • 如何计算我的 YouTube API 使用情况?

    我正在为客户构建一个相当大的应用程序 它将聚合来自各种来源的提要 我的客户估计 该系统一开始将有大约 900 个可关注的用户 随着时间的推移 还会增加更多用户 他希望每 15 分钟更新一次 feed 数据 因此我们需要每秒更新一个用户 fe
  • 在新窗口中运行 powershell

    我想使用参数运行新的 powershell 窗口 我试图运行以下命令 powershell Command get date 但一切都发生在同一个控制台中 有没有一种简单的方法可以做到这一点 要从 PowerShell 打开新的 Power
  • 为什么C++中没有sort(v)?

    我一直想知道为什么没有 sort v same as std sort v begin v end 如果我没记错的话 很久以前我看到过一个 boostcon 剪辑 演讲者说这个需要概念 但我不明白为什么 顺便说一句 我尝试了这个 在 VS
  • 将视频和贴纸图像分享到 Android 上的 Instagram Story

    如何将视频作为背景和图像作为贴纸一起分享到 Instagram Story 如果两个内容都是图像 则本文档只有一种解决方案 https developers facebook com docs instagram sharing to st
  • 如何使协议关联类型需要协议继承而不是协议采用

    在我的 swift 项目中 我有一个使用协议继承的情况 如下所示 protocol A class protocol B A 接下来我想要实现的是声明另一个具有关联类型的协议 该类型必须从协议继承A 如果我尝试将其声明为 protocol