繁体   English   中英

如何进行数组模式匹配

[英]How to do Array pattern matching

我正在寻找这样的东西:

switch array {
case []:
    print("No elements")
case let [x]:
    print(x)
case let [a, b]:
    print(a)
    print(b)
default:
    print("More than 2 elements")
}

有什么办法可以在 Swift 中实现吗?

你可以这样写,但如果你有多个元素,它很快就会变得笨拙:

switch array.count
{
   case 0 : print("No elements")

   case 1 : let x = array[0]
            print(x)

   case 2 : let (a,b) = (array[0],array[1])
            print(a)
            print(b)

   default: print("More than 2 elements")
}

我写了一些有史以来最愚蠢的代码来实现这样的目标。

for a in [ [], [0], [0,1], [0,1,2], [0,1,2,3,4], [0,1,2,3,4,5,6] ] {
    Switch(a) {
        Case { x in
            print("Singleton: \(x)")
        }
        Case { (x, y) in
            print("Pair: \(x), \(y)")
        }
        Case { (x, y, z) in
            print("Triple: \(x), \(y), \(z)")
        }
        Case(a.count == 4 || a.count == 5) {
            print("I didn't feel like splitting these up: \(a)")
        }
        Case(a.count >= 6) { () -> ControlFlow in // Type checker is too slow to leave the type out
            print("It's a big one: \(a)")
            return .fallthrough
        }
        Default {
            print("This falls out of range of the special overloads: \(a)")
        }
    }
}

// Implementation below
func Switch<T>(_ v: T, @SwitchBuilder<T> _ cases: () -> [Case<T>]) {
    var fallingThrough = false
    for c in cases() {
        if fallingThrough || c.match(v) {
            switch c.run(v) {
            case .break:
                return
            case .fallthrough:
                fallingThrough = true
            }
        }
    }
}
@resultBuilder
enum SwitchBuilder<T> {
    static func buildExpression(_ d: Default<T>) -> Case<T> {
        Case(d)
    }
    static func buildExpression(_ c: Case<T>) -> Case<T> {
        c
    }
    static func buildBlock(_ cs: Case<T>...) -> [Case<T>] {
        cs
    }
}
enum ControlFlow {
    case `break`
    // Be careful with this one, it's probably a bad idea.
    case `fallthrough`
}
struct Case<T> {
    var match: (T) -> Bool
    var run: (T) -> ControlFlow
    
    init(_ condition: @autoclosure @escaping () -> Bool, f: @escaping () -> ControlFlow) {
        self.match = { _ in condition() }
        self.run = { _ in f() }
    }
    init(_ condition: @autoclosure @escaping () -> Bool, f: @escaping () -> ()) {
        self.match = { _ in condition() }
        self.run = { _ in f(); return .break }
    }
    init<E>(_ f: @escaping (E) -> ControlFlow) where T == [E] {
        self.match = { $0.count == 1 }
        self.run = { f($0[0]) }
    }
    init<E>(_ f: @escaping (E) -> ()) where T == [E] {
        self.match = { $0.count == 1 }
        self.run = { f($0[0]); return .break }
    }
    init<E>(_ f: @escaping (E,E) -> ControlFlow) where T == [E] {
        self.match = { $0.count == 2 }
        self.run = { f($0[0], $0[1]) }
    }
    init<E>(_ f: @escaping (E,E) -> ()) where T == [E] {
        self.match = { $0.count == 2 }
        self.run = { f($0[0], $0[1]); return .break }
    }
    init<E>(_ f: @escaping (E,E,E) -> ControlFlow) where T == [E] {
        self.match = { $0.count == 3 }
        self.run = { f($0[0], $0[1], $0[2]) }
    }
    init<E>(_ f: @escaping (E,E,E) -> ()) where T == [E] {
        self.match = { $0.count == 3 }
        self.run = { f($0[0], $0[1], $0[2]); return .break }
    }
    init<E>(_ f: @escaping (E,E,E,E) -> ControlFlow) where T == [E] {
        self.match = { $0.count == 4 }
        self.run = { f($0[0], $0[1], $0[2], $0[3]) }
    }
    init<E>(_ f: @escaping (E,E,E,E) -> ()) where T == [E] {
        self.match = { $0.count == 4 }
        self.run = { f($0[0], $0[1], $0[2], $0[3]); return .break }
    }
    init<E>(_ f: @escaping (E,E,E,E,E) -> ControlFlow) where T == [E] {
        self.match = { $0.count == 5 }
        self.run = { f($0[0], $0[1], $0[2], $0[3], $0[4]) }
    }
    init<E>(_ f: @escaping (E,E,E,E,E) -> ()) where T == [E] {
        self.match = { $0.count == 5 }
        self.run = { f($0[0], $0[1], $0[2], $0[3], $0[4]); return .break }
    }
    init(_ d: Default<T>) {
        self.match = { _ in true }
        self.run = d.run
    }
}
struct Default<T> {
    var run: (T) -> ControlFlow
    
    init(_ f: @escaping () -> ControlFlow) {
        self.run = { _ in f() }
    }
    init(_ f: @escaping () -> ()) {
        self.run = { _ in f(); return .break }
    }
}

正如您所希望的那样,这会打印

This falls out of range of the special overloads: []
Singleton: 0
Pair: 0, 1
Triple: 0, 1, 2
I didn't feel like splitting these up: [0, 1, 2, 3, 4]
It's a big one: [0, 1, 2, 3, 4, 5, 6]
This falls out of range of the special overloads: [0, 1, 2, 3, 4, 5, 6]

这个实现只允许你解构长度为 5 的数组,但是通过向Case添加额外的初始值设定项来添加更多案例是微不足道的。 除了如何使用它之外,Swift 不知道这意味着什么,因此您将无法使用它从您的函数return (在Casereturn就像在正常case break case )或初始化变量,并且没有强制执行违约。

请不要在实际项目中使用它。 或者,我只是一个互联网上的人,你不必听我的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM