如何模式符合协议的匹配类型

时间:2015-12-29 13:04:14

标签: swift pattern-matching protocols

我想编写与此类型模式匹配的函数(只是示例代码):

protocol Event {}

enum LightsEvent: Event {
    case SwitchOn
    case SwitchOff
}

enum CameraEvent: Event {
    case Rolling
    case Cut
}

struct EventHandler {
    let event: Event

    func handle(event: LightsEvent) {
        // do something with lights
    }

    func handle(event: CameraEvent) {
        // do something with camera
    }
}

let handler = EventHandler(event: LightsEvent.SwitchOn)
handler.handle(handler.event) // error: Cannot invoke 'handle' with type ('Event')

我觉得应该编译,但事实并非如此。这迫使我添加一个像这样的开关函数:

func handle(event: Event) {
        switch event {
        case let e as LightsEvent: handle(e)
        case let e as CameraEvent: handle(e)
        default: fatalError()
        }
    }

但是每次我向处理程序添加其他类型的事件时,我都不想为此开关添加另一个案例。有谁知道如何更优雅地解决这个问题?

2 个答案:

答案 0 :(得分:1)

EventHandler添加泛型将使其有效:

struct EventHandler<T: Event> {
    let event: T

    func handle(event: LightsEvent) {
        print("lights: \(event)");
    }

    func handle(event: CameraEvent) {
        print("camera: \(event)");
    }
}

let handler = EventHandler(event: LightsEvent.SwitchOn)
handler.handle(handler.event)

然而,这仍然不够优雅,因为我们在构建EventHandler时以及调用handle方法时两次传递相同的事件。

您也无法在EventHandler中保留对该事件的引用,因为它可能不需要,只需要处理它:

struct EventHandler {

    func handle(event: LightsEvent) {
        print("lights: \(event)");
    }

    func handle(event: CameraEvent) {
        print("camera: \(event)");
    }
}

let handler = EventHandler()
handler.handle(LightsEvent.SwitchOn)

答案 1 :(得分:0)

protocol Event {}

enum Events : Event {
    case One, Two
}

struct EventHandler {
    let event: Events

    func handle<T: Event>(event: T) {
        print(event)
    }
}

let handler = EventHandler(event: Events.Two)
handler.handle(handler.event) // prints "Two"

但是,如果您只想将协议用作空虚拟类型约束,那么您也可以删除它并只删除枚举

enum Events {
    case One, Two
}

struct EventHandler {
    let event: Events

    func handle(event: Events) {
        print(event)
    }
}

let handler = EventHandler(event: Events.Two)
handler.handle(handler.event) // prints "Two"