草庐IT

generics - 通用类的 Swift 委托(delegate)协议(protocol)

coder 2023-09-04 原文

我有一个类 StateMachine,它是通用的,允许将不同的状态集实现为枚举。我想使用 StateMachineDelegate 协议(protocol)在状态机进入新状态时通知委托(delegate)。

但这行不通,因为委托(delegate)协议(protocol)对于类型要求也是通用的。该错误显示声明 delegate 属性的位置。

protocol StateType: Hashable {}

protocol StateMachineDelegate: class {
    typealias S: StateType
    func stateMachine(stateMachine: StateMachine<S>, didEnterState newState: S)
}

class StateMachine<S: StateType> {
    typealias State = S

    weak var delegate: StateMachineDelegate?
    //~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
    //Protocol 'StateMachineDelegate' can only be used as a generic constraint because it has Self or associated type requirements

    var currentState: State {...}

    init(initialState: State) {...}

    func applyState(toState: State) -> Bool {
        ...
        currentState = toState
        delegate?.stateMachine(self, didEnterState: toState)
        ...
    }
}



我需要以某种方式关联 StateMachine 类中的 StateMachineDelegate.S == S,但我不确定如何执行此操作,或者是否可能。我试过:

class StateMachine<S: StateType, D: StateMachineDelegate where D.S == S> {
    ...
    weak var delegate: D?
    ...
}

但后来我在尝试重新编写协议(protocol)以正确声明 StateMachine 的通用类型时陷入困境。在创建 StateMachine 时必须预先声明委托(delegate)的类型似乎是不对的。

最佳答案

查看此解决方法是否适合您的需求,它使用 @autoclosure 来消除递归泛型定义的问题:

class StateMachine<S: Printable, D: StateMachineDelegate where S == D.StateType> {

    var currentState: S {
        didSet {
            // The observer
            if let delegate = self.delegate {
                delegate.stateMachine(self, didEnterState: self.currentState)
            }
        }
    }

    var delegate: D?

    init(initialState: S) {
        self.currentState = initialState
    }


}


protocol StateMachineDelegate: class {
    typealias StateType: Printable

    // Workaround with autoclosure
    func stateMachine(machine: @autoclosure() -> StateMachine<StateType, Self>, didEnterState newState: StateType)
}

final class ADelegate: StateMachineDelegate {
    typealias StateType = Int
    func stateMachine(machine: @autoclosure  () -> StateMachine<StateType, ADelegate>, didEnterState newState: StateType) {
        // Need to _unbox_ the sander from the closure
        let sender = machine()
        println(newState)
        println("State from sender: \(sender.currentState)")
    }
}

let stateMachine = StateMachine<Int, ADelegate>(initialState: 24)

stateMachine.delegate = ADelegate()
stateMachine.currentState = 50

顺便说一句,考虑一下,如果你得到了打磨机,你可能不需要通过 newState。 在示例中,我使用 Printable 代替 Hashable

关于generics - 通用类的 Swift 委托(delegate)协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28213966/

有关generics - 通用类的 Swift 委托(delegate)协议(protocol)的更多相关文章

  1. ruby-on-rails - 使用 config.threadsafe 时从 lib/加载模块/类的正确方法是什么!选项? - 2

    我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co

  2. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  3. 没有类的 Ruby 方法? - 2

    大家好!我想知道Ruby中未使用语法ClassName.method_name调用的方法是如何工作的。我头脑中的一些是puts、print、gets、chomp。可以在不使用点运算符的情况下调用这些方法。为什么是这样?他们来自哪里?我怎样才能看到这些方法的完整列表? 最佳答案 Kernel中的所有方法都可用于Object类的所有对象或从Object派生的任何类。您可以使用Kernel.instance_methods列出它们。 关于没有类的Ruby方法?,我们在StackOverflow

  4. ruby - Rails 关联 - 同一个类的多个 has_one 关系 - 2

    我的问题的一个例子是体育游戏。一场体育比赛有两支球队,一支主队和一支客队。我的事件记录模型如下:classTeam"Team"has_one:away_team,:class_name=>"Team"end我希望能够通过游戏访问一个团队,例如:Game.find(1).home_team但我收到一个单元化常量错误:Game::team。谁能告诉我我做错了什么?谢谢, 最佳答案 如果Gamehas_one:team那么Rails假设您的teams表有一个game_id列。不过,您想要的是games表有一个team_id列,在这种情况下

  5. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  6. ruby - 为什么当我调用类的实例方法时,初始化不显示为方法? - 2

    我正在写一篇关于在Ruby中几乎一切都是对象的博客文章,我试图通过以下示例来展示这一点:classCoolBeansattr_accessor:beansdefinitialize@bean=[]enddefcount_beans@beans.countendend所以从类中我们可以看出它有4个方法(当然,除非我错了):它可以在创建新实例时初始化一个默认的空bean数组它可以计算它有多少个bean它可以读取它有多少个bean(通过attr_accessor)它可以向空数组写入(或添加)更多bean(也通过attr_accessor)但是,当我询问类本身它有哪些实例方法时,我没有看到默认

  7. ruby-on-rails - Rails 中同一个类的多个关联的最佳实践? - 2

    我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来

  8. ruby - 从外部访问类的实例变量 - 2

    我理解(我认为)Ruby中类变量和类的实例变量之间的区别。我想知道如何从该类外部访问该类的实例变量。从内部(即在类方法中而不是实例方法中),它可以直接访问,但是从外部,有没有办法做MyClass.class.[@$#]variablename?我没有任何具体原因要这样做,只是学习Ruby并想知道是否可行。 最佳答案 classMyClass@my_class_instance_var="foo"class上述yield:>>foo我相信Arkku演示了如何从类外部访问类变量(@@),而不是类实例变量(@)。我从这篇文章中提取了上述内

  9. ruby-on-rails - Resque - 类的未定义方法 'perform' - 2

    我目前对后台队列不太满意。我正在尝试让Resque工作。我已经安装了redis和Resquegem。Redis正在运行。一个worker正在运行(rakeresque:workQUEUE=simple)。使用Web界面,我可以看到工作人员正在运行并等待工作。当我运行“rakeget_updates”时,作业已排队但失败了。我已经用defself.perform和defperform试过了。发条.raketask:get_updates=>:environmentdoResque.enqueue(GetUpdates)end类文件(app/workers/get_updates.rb)c

  10. ruby - 将属性方法委托(delegate)给父对象 - 2

    我有以下类(class):classAlphabetattr_reader:letter_freqs,:statistic_letterdefinitialize(lang)@lang=langcaselangwhen:en@alphabet=('A'..'Z').to_a@letter_freqs={...}when:ru@alphabet=('А'..'Я').to_a.insert(6,'Ё')@letter_freqs={...}...end@statistic_letter=@letter_freqs.max_by{|k,v|v}[0]endendfoo=Alphabet.n

随机推荐