如何在Swift中检查类型是否为Optional?

时间:2017-12-07 07:57:52

标签: swift optional

如何在Swift中检查类型是否为Optional?

假设我有一个PartialKeyPath类型的变量,其中:

struct Foo {
    let bar: String
    let baz: String?
}

typealias Property<Root> = (key: PartialKeyPath<Root>, value: Any?)
typealias Properties<Root> = [Property<Root>]

现在说我通过一个属性实例进行迭代:

properties.forEach { prop in
    let valueType1 = type(of: prop.key).valueType
    let valueType2 = type(of: value)

    ...

我如何在此检查valueType1是Optional<valueType2>,还是其他任何风格的可选项?

到目前为止,我找到的唯一方法真的很丑......

4 个答案:

答案 0 :(得分:3)

使用与Optional field type doesn't conform protocol in Swift 3类似的方法,您可以定义一个虚拟协议&#39;对于Optional并使用它来获取包装的元类型:

protocol OptionalProtocol {
  // the metatype value for the wrapped type.
  static var wrappedType: Any.Type { get }
}

extension Optional : OptionalProtocol {
  static var wrappedType: Any.Type { return Wrapped.self }
}

如果你只是想知道一个类型是可选的:

func isOptionalType(_ type: Any.Type) -> Bool {
  return type is OptionalProtocol.Type
}

print(isOptionalType(String.self)) // false
print(isOptionalType(String?.self)) // true

如果你想检查一个元类型是否是可选版本&#39;另一种元型:

struct Foo {
  let bar: String
  let baz: String?
}

struct Property<Root> {
  var key: PartialKeyPath<Root>
  var value: Any
}

let properties = [Property(key: \Foo.baz, value: "hello")]

/// Attempt to get the `Wrapped` metatype from a metatype of an
/// `Optional<Wrapped>`. If not an `Optional`, will return `nil`.
func wrappedTypeFromOptionalType(_ type: Any.Type) -> Any.Type? {
  return (type as? OptionalProtocol.Type)?.wrappedType
}

for property in properties {
  let valueType1 = type(of: property.key).valueType
  let valueType2 = type(of: property.value)

  if wrappedTypeFromOptionalType(valueType1) == valueType2 {
    print("\(valueType1) == Optional<\(valueType2)>")
  }
}

// Optional<String> == Optional<String>

然而,几乎可以肯定的是,你可以通过关键路径做更好的事情。

答案 1 :(得分:1)

你可以使用反映Any的镜像并检查displayStyle是可选的吗?。

func isOptional(any:Any) -> Bool {

  let mirror = Mirror(reflecting: any)
  if mirror.displayStyle == .Optional {
      return true
  } else {
      return false
  }

}

有关镜像显示风格的更多信息: https://developer.apple.com/documentation/swift/mirror.displaystyle

答案 2 :(得分:1)

这是一个hacky但工作正常的解决方案:

func isOptional(_ type: Any.Type) -> Bool {
    let typeName = String(describing: type)
    return typeName.hasPrefix("Optional<")
}

测试:

let t1 = Int?.self
let t2 = Bool.self

print(isOptional(t1))
// true

print(isOptional(t2))
// false

答案 3 :(得分:0)

@ kelin回答的调整:

postfix operator ...?!
postfix func ...?!<T>(_ instance: T) -> Bool {
    let subject = "\(Mirror(reflecting: instance).subjectType)"
    return !subject.hasPrefix("Optional") 
}

@ Ercell0的答案是这种优越的方法:

func isOptional<T>(_ instance: T) -> Bool {
    guard let displayStyle = Mirror(reflecting: instance).displayStyle 
        else { return false }
    return displayStyle == .optional
}