对于某些情况,我有一个带有相关值的枚举:
enum Foo {
case a
case b
case c(String?)
}
我还有一个带有此枚举的结构作为变量
struct Bar {
var foo: Foo
}
然后我有一个这个对象的数组
let array:[Bar] = [Bar(foo: .a), Bar(foo: .c(nil)), Bar(foo: .c("someString"))]
我想基于它收到类似
的情况创建一个对该数组的子集进行操作的函数func printOnly(objectsWithCase: Foo)
到目前为止它非常简单,但现在这里有一个问题:对于这个操作,我想要忽略相关的值。
我想让这个函数能够在不提及相关值的情况下采用.c
个案,就像说“给我.c
的那个而不管相关的值”。
我换句话说 - 我想传递像.c(_)
这样的东西(当然这不起作用)并让它返回(在这种情况下打印)Bar(foo: .c(nil))
和{{1 }}
到目前为止,我只想出更改函数声明来进行过滤关闭而不是像这样的情况:
Bar(foo: .c("someString"))
我想知道是否有办法在Swift中执行此操作,同时传递案例而不是条件块?
答案 0 :(得分:2)
您可以在模式匹配操作中将下划线用作外卡:
array.filter {
switch $0.foo {
case .a: return true // keep a
case .b: return false // reject b
case .c(_): return true // keep c, regardless of assoc. value.
}
}
答案 1 :(得分:1)
//: Playground - noun: a place where people can play
enum Foo {
case a
case b
case c(String?)
}
struct Bar {
var foo: Foo
}
let array:[Bar] = [Bar(foo: .a), Bar(foo: .c(nil)), Bar(foo: .c("someString"))]
func printArray(array: [Bar], condition: (Bar) -> Bool) {
let tmp = array.filter(condition)
print(tmp)
}
printArray(array: array) { bar in
switch bar.foo {
case .c:
return true
default:
return false
}
}
或
printArray(array: array) { bar in
if case let Foo.c = bar.foo {
return true
}
return false
}
修改强>
//: Playground - noun: a place where people can play
enum Foo: Equatable {
case a
case b
case c(String?)
}
func ==(lhs: Foo, rhs: Foo) -> Bool {
switch (lhs, rhs) {
case (.a, .a), (.b, .b), (.c, .c):
return true
default:
return false
}
}
struct Bar {
var foo: Foo
}
let array:[Bar] = [Bar(foo: .a), Bar(foo: .c(nil)), Bar(foo: .c("someString"))]
func printArray(array: [Bar], condition: (Bar) -> Bool) {
let tmp = array.filter(condition)
print(tmp)
}
func printOnly(objectsWithCase wantedCase: Foo) {
printArray(array: array) { bar in
if wantedCase == bar.foo {
return true
} else {
return false
}
}
}
printOnly(objectsWithCase:.c(nil))
答案 2 :(得分:1)
虽然这在技术上并不是你所要求的(我不认为有任何方法可以通过枚举来实现这一点),你可以编写一个“假”枚举,其中包含一个匹配任何你的通配符c
想。这将为您提供完全相同的语法。
1)将Foo
替换为以下
struct Foo: Equatable {
let rawValue: String
let associatedObject: String?
let isWildcard: Bool
fileprivate init(rawValue: String, associatedObject: String?, isWildcard: Bool) {
self.rawValue = rawValue
self.associatedObject = associatedObject
self.isWildcard = isWildcard
}
static var a: Foo {
return Foo(rawValue: "a", associatedObject: nil, isWildcard: false)
}
static var b: Foo {
return Foo(rawValue: "b", associatedObject: nil, isWildcard: false)
}
static var c: Foo {
return Foo(rawValue: "c", associatedObject: nil, isWildcard: true)
}
static func c(_ value: String?) -> Foo {
return Foo(rawValue: "c", associatedObject: value, isWildcard: false)
}
}
func ==(left: Foo, right: Foo) -> Bool {
// Match rawValue + associatedObject unless we have a wildcard
return (left.rawValue == right.rawValue)
&& (left.associatedObject == right.associatedObject || left.isWilcard || right.isWildcard)
}
2)使用printOnly
==
功能
func printOnly(objects: [Bar], with match: Foo) {
objects.filter { $0.foo == match }.forEach { print($0) }
}
3)成功
printOnly(objects: array, with: .c) // [.c(nil), .c("someString")]
<强>讨论强>
除了额外的样板代码之外,此方法的主要缺点是您必须创建不应允许的枚举值。此方法将您的责任仅用作通配符,而不是真正的枚举值。它也不能保证您无法创建其他枚举案例,尽管您应该能够通过制作唯一的初始化程序fileprivate
来缓解这种情况。
否则,这会给你完全相同的界面和enum给你的功能,你可以像以前一样定义你的案例
let array = [Bar(foo: .a), Bar(foo: .c(nil)), Bar(foo: .c("Hello")]
最后,您仍然可以在交换机中使用它,除非您始终需要添加default
语句。
switch Foo.c("Hello") {
case .a:
print("A")
case .b:
print("B")
case .c: // will match .c(nil) and .c("someString")
print("C")
default:
break
}