协议类型数组

2024-03-31

我已经在 stackoverflow 上检查了有关此问题的所有答案,但仍然不知道如何解决此问题。 我的模型看起来像这样

protocol Commandable: Equatable {
    var condition: Condition? {get set}

    func execute() -> SKAction
}

以及实现该协议的 3 个结构体

struct MoveCommand: Commandable {

    var movingVector: CGVector!

    //MARK: - Commandable

    var condition: Condition?
    func execute() -> SKAction {
       ...
    }
}

extension MoveCommand {
    // MARK:- Equatable

    static func ==(lhs: MoveCommand, rhs: MoveCommand) -> Bool {
        return lhs.movingVector == rhs.movingVector && lhs.condition == rhs.condition
    }
}

struct RotateCommand: Commandable {
    var side: RotationSide!

    // MARK: - Commandable

    var condition: Condition?
    func execute() -> SKAction {
        ...
    }
}

extension RotateCommand {
    // MARK: - Equatable
    static func ==(lhs: RotateCommand, rhs: RotateCommand) -> Bool {
        return lhs.side == rhs.side && lhs.condition == rhs.condition
    }
}

当我尝试创建具有 [Commandable] 数组的第三个结构时,问题就开始了:

struct FunctionCommand: Commandable {
    var commands = [Commandable]()

编译器输出:Protocol 'Commandable' can only be used as a generic constraint because it has Self or associated type requirements。然后我用这种方式重写了我的结构:

struct FunctionCommand<T : Equatable>: Commandable {
    var commands = [T]()

我解决了这个问题,但又出现了新的问题。现在我无法创建FunctionCommand使用“旋转”和“移动”命令的实例,仅使用其中之一的实例 :( :

let f = FunctionCommand(commands: [MoveCommand(movingVector: .zero, condition: nil), 
RotateCommand(side: .left, condition: nil)], condition: nil)

任何帮助,将不胜感激。

Update:那篇文章帮助我弄清楚了 -https://krakendev.io/blog/generic-protocols-and-their-shortcomings https://krakendev.io/blog/generic-protocols-and-their-shortcomings


您需要做的是使用类型擦除,就像AnyHashable在 Swift 标准库中。

你不能这样做:

var a: [Hashable] = [5, "Yo"]
// error: protocol 'Hashable' can only be used as a generic constraint because it has Self or associated type requirements

你要做的就是使用类型擦除类型AnyHashable:

var a: [AnyHashable] = [AnyHashable(5), AnyHashable("Yo")]
a[0].hashValue // => shows 5 in a playground

所以你的解决方案是首先将协议分成更小的部分并推广Equatable to Hashable(重复使用AnyHashable)

protocol Conditionable {
    var condition: Condition? { get set }
}

protocol Executable {
    func execute() -> SKAction
}

protocol Commandable: Hashable, Executable, Conditionable {}

然后创建一个AnyCommandable结构体,像这样:

struct AnyCommandable: Commandable, Equatable {
    var exeBase: Executable
    var condBase: Conditionable
    var eqBase: AnyHashable

    init<T: Commandable>(_ commandable: T) where T : Equatable {
        self.condBase = commandable
        self.exeBase = commandable
        self.eqBase = AnyHashable(commandable)
    }

    var condition: Condition? {
        get {
            return condBase.condition
        }
        set {
            condBase.condition = condition
        }
    }

    var hashValue: Int {
        return eqBase.hashValue
    }

    func execute() -> SKAction {
        return exeBase.execute()
    }

    public static func ==(lhs: AnyCommandable, rhs: AnyCommandable) -> Bool {
        return lhs.eqBase == rhs.eqBase
    }
}

然后你可以像这样使用它:

var a = FunctionCommand()
a.commands = [AnyCommandable(MoveCommand()), AnyCommandable(FunctionCommand())]

并且您可以轻松访问的属性commands, 因为AnyCommandable实施Commandable

a.commands[0].condition

您需要记住现在添加Hashable and Equatable听从您的所有命令。 我使用这些实现进行测试:

struct MoveCommand: Commandable {

    var movingVector: CGVector!

    var condition: Condition?
    func execute() -> SKAction {
        return SKAction()
    }

    var hashValue: Int {
        return Int(movingVector.dx) * Int(movingVector.dy)
    }

    public static func ==(lhs: MoveCommand, rhs: MoveCommand) -> Bool {
        return lhs.movingVector == rhs.movingVector
    }
}

struct FunctionCommand: Commandable {
    var commands = [AnyCommandable]()

    var condition: Condition?

    func execute() -> SKAction {
        return SKAction.group(commands.map { $0.execute() })
    }

    var hashValue: Int {
        return commands.count
    }

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

协议类型数组 的相关文章

随机推荐

  • 实时搜索:用户输入完毕后开始搜索

    在我的应用程序中 当用户在文本字段中键入内容时 我正在搜索结果 我正在使用 Provider 其中有一个 searchProduct 函数 每次用户在文本字段中键入内容时都会触发该函数 获取结果后 我将调用 notificationList
  • 使用片段的Android功能区菜单

    我使用水平滚动视图对功能区菜单进行了编码 我的代码如下 public class HorzScrollWithListMenuActivity extends Activity MyHorizontalScrollView scrollVi
  • JQuery Mobile 加载更多选项

    知道如何在 JQueryMobile 中实现加载更多选项 在我的应用程序中 我需要提取大量数据 并希望加载前 20 条数据 并让用户通过单击 Listview 最后一行上的 加载更多 数据选项来加载更多数据 这应该有效 loadmore l
  • Oracle Tuxedo 的节省成本替代方案 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 Oracle Tuxedo 中间件平台有哪些节省成本的替代方案 可以将现有代码库迁移到该平台 很少有开源
  • Access/SQL Server 2008 使用 Like 加入不起作用

    我提前道歉 因为这个问题在这个网站上多次以各种形式出现 但我尝试实施的解决方案似乎都无法正常工作 而且我找不到可以得到正确答案的已回答问题 我正在为一位同事从事 Access 工作 不过一旦他能够设置服务器 将来可能会使用 SQL 我正在尝
  • elm 中的“<<”运算符是什么意思?

    以下代码取自榆树形式示例 http elm lang org edit examples Intermediate Form elm 第 122 行 什么是 lt lt 运算符的意思是 Field field Field defaultSt
  • EaselJS:单击鼠标更改形状填充颜色

    我在使用 EaselJS 时遇到了困难 基本上我想创建一个简单的网格并突出显示所选的实际元素 var stageWidth 800 stageHeight 600 cell size 50 w 16 h 12 n w h canvas st
  • 为什么 ViewPager2 延迟加载页面? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我决定尝试一下现在可用的新稳定版本ViewPager2 My ViewPager2有很多页面 我正在使用TabLayout为每个页面 片段 提供
  • 单击即可在 FullCalendar 中添加事件

    我正在尝试在 NET 中的日历单元格单击上添加事件 如下所示 http arshaw com js fullcalendar 1 5 3 demos selectable html http arshaw com js fullcalend
  • 如何在 C# 中使用 TaskScheduler 设置“仅在登录时运行”和“运行方式”?

    我有使用 C TaskManager 对象创建任务的代码 在 Windows 7 上它工作正常 但在 Windows XP 可能还有其他 Windows 上它根本不起作用 因为任务的默认用户是系统 因此没有用于显示 GUI 的会话 如果我在
  • 从 DOM 中删除元素并将它们添加回原来的位置

    我有一个模态窗口 我想要发生的事情是在模式打开时从页面中删除某些元素 并在模式关闭后将它们添加回原来的位置 我不想显示 无 因为这只会隐藏它们 我需要将它们实际从页面中删除 所以我有一些 jQuery 需要删除并在计时器之后将它们添加回来
  • PHP 的 shuffle 函数有多随机?

    有谁知道PHP的随机性是什么shuffle 功能 它取决于操作系统吗 它使用 PHP 自己的播种器吗 是否可以使用mt rand 作为发电机 shuffle 函数基于相同的生成器rand 这是基于的系统生成器线性同余算法 http en w
  • 使用“Lazy Eager Loading”返回关系中的第一个元素 [Laravel 5.2]

    我有这样的关系 public function message return this gt hasMany Engine Message 在我的里面Conversation model 对于每次对话 我都需要获取最后一条消息 这是我尝试过
  • 自动为所有可能的线性模型创建公式

    假设我在数据框中有一个训练集train有柱子ColA ColB ColC等 这些列之一指定一个二进制类 例如列Class 具有 是 或 否 值 我正在尝试一些二元分类器 例如 library klaR mynb lt NaiveBayes
  • Xcode 9 - CPU 使用率高 - 风扇最大速度

    自从我升级到 Xcode 9 后 当我在 Xcode 上工作时 我的粉丝就变得疯狂了 当我使用 Storyboards 和 Interface Builder 时 尤其会发生这种情况 Xcode有时会占用100 的CPU 并且名为 Inte
  • Weifenluo Dock Panel Suite:浮动窗口使用其设计尺寸?

    如何使用 Weifenluo Dockpanel 套件使浮动窗口使用其设计尺寸 而不是 Dock Panel 套件的默认尺寸 提示 我尝试了 SF net 上 Dock Panel Suite 论坛的建议 但这似乎不起作用 我自己寻找答案时
  • 为什么我们需要 IEqualityComparer,IEqualityComparer 接口?

    Equal 和 GetHashcode 方法存在于对象类中 并且我们的类型继承了对象基类 直接实现对象的两个方法和使用IComparer接口有什么区别 如果我们覆盖对象的 Equal 和 GetHashCode 并推送到哈希表 它将使用覆盖
  • 使用 serde 序列化结构时如何展平“Vec”字段?

    我有一些 XML 它的标签包含多个同名的同级标签 如下所示
  • 强制终止子进程的Java工具/方法

    我正在寻找一个 Java 工具 包 库 可以让我强制杀死 一个子进程 该工具 包 库必须在 Windows 平台上运行 强制 需要对 Linux Unix 的支持 我的问题 我的 Java 代码创建了一个子进程 它根本不会对 杀死子进程的标
  • 协议类型数组

    我已经在 stackoverflow 上检查了有关此问题的所有答案 但仍然不知道如何解决此问题 我的模型看起来像这样 protocol Commandable Equatable var condition Condition get se