自定义模式匹配失败,并显示“枚举大小写不是类型的成员”



我正在尝试编写一个自定义模式匹配,让我打开错误并与错误代码匹配。请参阅以下示例:

enum ErrorCode: Int {
  case notSoDumb
  case dumbError
}
let myError = NSError(domain: "My domain", code: ErrorCode.dumbError.rawValue, userInfo: nil)
func ~=(pattern: ErrorCode, value: NSError) -> Bool {
  return (ErrorCode(rawValue: value.code) == pattern)
}
switch myError {
case ErrorCode.notSoDumb:
  print("Not a dumb error")
case ErrorCode.dumbError:
  print("Super dumb error")
default:
  print("No matches!")
}

我的switch语句中的第一种情况错误为Enum case 'notSoDumb' is not a member of type 'NSError'。如果我用整数替换ErrorCode枚举(并更新我的自定义~=运算符以匹配 Int s 和 NSError s,一切正常。

这是一个已知的错误,在模式匹配中enum事例;编译器错误地假定它始终使用枚举大小写模式而不是表达式模式。

在修复之前,强制编译器进入"表达式模式模式"的一种方法是首先临时绑定大小写:

let notSoDumbErrorCode = ErrorCode.notSoDumb
let dumbErrorCode = ErrorCode.dumbError
switch myError {
case notSoDumbErrorCode:
  print("Not a dumb error")
case dumbErrorCode:
  print("Super dumb error")
default:
  print("No matches!")
}

然而,这非常笨拙。也许更好的解决方法是使用具有静态成员而不是enumstruct

import Foundation
struct ErrorCode : Equatable, RawRepresentable {
  let rawValue: Int
  static let notSoDumb = ErrorCode(rawValue: 0)
  static let dumbError = ErrorCode(rawValue: 1)
}
let myError = NSError(domain: "My domain",
                      code: ErrorCode.dumbError.rawValue,
                      userInfo: nil)
func ~=(pattern: ErrorCode, value: NSError) -> Bool {
  return value.code == pattern.rawValue
}
switch myError {
case ErrorCode.notSoDumb:
  print("Not a dumb error")
case ErrorCode.dumbError:
  print("Super dumb error")
default:
  print("No matches!")
}

这也使您能够稍后通过扩展添加其他错误代码(它的行为更像是一个开放的枚举)。尽管它确实从init(rawValue:)中删除了验证,但这可能是可取的,也可能不是可取的(不过,您始终可以实现自己的init?(rawValue:))。

或者,正如您在评论中所说,您可以坚持使用 enum ,但在模式匹配时使用中间函数调用以强制编译器进入"表达式模式":

enum ErrorCode : Int {
  case notSoDumb
  case dumbError
}
// ...
func identity<T>(_ t: T) -> T { return t }
switch myError {
case identity(ErrorCode.notSoDumb):
  print("Not a dumb error")
case identity(ErrorCode.dumbError):
  print("Super dumb error")
default:
  print("No matches!")
}

有趣的是,尽管答案中链接的错误仍然@Hamish打开,但现在它可以编译并工作:

import Foundation
enum ErrorCode: Int {
    case notSoDumb
    case dumbError
}
let myError = NSError(domain: "My domain", code: ErrorCode.dumbError.rawValue, userInfo: nil)
func ~=(pattern: ErrorCode, value: NSError) -> Bool {
    return (ErrorCode(rawValue: value.code) == pattern)
}
switch myError {
case .notSoDumb:
    print("Not a dumb error")
case .dumbError:
    print("Super dumb error") // "Super dumb errorn"
default:
    print("No matches!")
}

我最好的猜测是这与SE-0287有关

最新更新