确定 Any.Type 是否为可选

问题描述 投票:0回答:7

我正在尝试确定给定类型

t
Any.Type
)是否是可选类型,我正在使用此测试

t is Optional<Any>.Type

但它总是返回 false。

那么有什么办法可以实现这一点吗?

swift dynamic
7个回答
29
投票

假设您正在尝试做的是这样的:

let anyType: Any.Type = Optional<String>.self
anyType is Optional<Any>.Type // false

遗憾的是,Swift 目前(从 Swift 2 开始)不支持 协变或逆变 并且无法直接针对

Optional.Type
进行类型检查:

// Argument for generic parameter 'Wrapped' could not be inferred
anyType is Optional.Type // Causes error

另一种方法是使

Optional
扩展特定协议,并检查该类型:

protocol OptionalProtocol {}

extension Optional : OptionalProtocol {}

let anyType: Any.Type = Optional<String>.self
anyType is OptionalProtocol.Type // true

14
投票

聚会有点晚了。 但是,我遇到了同样的问题。 这是我的代码。

func isOptional(_ instance: Any) -> Bool {
    let mirror = Mirror(reflecting: instance)
    let style = mirror.displayStyle
    return style == .optional
}

let a: Int = 1 // false
let b: Int? = 2 // true
let c: Double = 3.0 // false
let d: Double? = 4.0 // true
let e: NSString = "Hello" // false
let f: NSString? = "Hello" // true


isOptional(a) // fasle
isOptional(b) // true - warning
isOptional(c) // false
isOptional(d) // true - warning
isOptional(e) // false
isOptional(f) // true - warning

我觉得不错。

swift4


4
投票

选项符合

ExpressibleByNilLiteral
,所以你可以使用它:

let t = Optional<String>.self
t is ExpressibleByNilLiteral.Type // true

2
投票

你可以这样做:

extension Mirror {
    static func isOptional(any: Any) -> Bool {
        guard let style = Mirror(reflecting: any).displayStyle,
            style == .optional else { return false }
        return true
    }
}

用途:

XCTAssertTrue(Mirror.isOptional(any: Optional(1)))

或者如果您需要从“任意”转换为“可选”

protocol _Optional {
    var isNil: Bool { get }
}

extension Optional: _Optional {
    var isNil: Bool { return self == nil }
}

func isNil (_ input: Any) -> Bool {
    return (input as? _Optional)?.isNil ?? false
}

用途:

isNil(nil as String?) // true
isNil("") // false

1
投票

你可以这样做:

public func isOptionalType(_ type: Any.Type) -> Bool {
  type is ExpressibleByNilLiteral.Type
  // or
  // String(describing: type).hasPrefix("Optional<")
}
(lldb) po isOptionalType(Int.self)
false

(lldb) po isOptionalType(Int?.self)
true

0
投票

我建议使用内置的

_isOptional()
功能。它内置于标准库中,尽管它带有下划线,这意味着它是私有的。然而,它是 ABI 的一部分,因此据我了解,目前将其删除是相当不可行的。

我编写了一个基准测试,比较了 StackOverflow 上提交的各种方法:

  1. _isOptional
    ,由Div这里
  2. 建议
  3. `是可选协议,由 Maic López Sáenz here
  4. 建议
  5. 使用
    Mirror
    ,首先由Kaz Yoshikawa这里
  6. 建议

方法 1 和 2 在可选情况下都更快,但方法 1 在非可选情况下快 10 倍以上。

方法 可选 对于非可选
_isOptional()
6 毫秒 5 毫秒
is OptionalProtocol
4 毫秒 63 毫秒
使用
Mirror
716 毫秒 388 毫秒

基于

Mirror
的方法也会产生一些内存分配,而其他方法则不会:

方法 可选 对于非可选
_isOptional()
0 0
is OptionalProtocol
0 0
使用
Mirror
4 3

有关更多信息,请参阅完整结果


-4
投票

您可以使用泛型来实现这一点:

func isOptional<T>(x:T?)->Bool
{
    return true
}

func isOptional<T>(x:T)->Bool
{
    return false
}

编辑

上面的代码可以用来判断一个变量是否是可选类型。 我想出了解变量包含类型的唯一方法是使用反射:

var t1:Any.Type=(String?).self
var t2:Any.Type=(String).self
Mirror(reflecting: t1).description
Mirror(reflecting: t2).description

第一次调用 Mirror 会给出字符串

"Mirror for Optional<String>.Type"
,第二次调用会给出
"Mirror for String.Type"

我知道比较字符串并不是进行此检查的便捷方法,我将再次尝试寻找更高效的方法..

© www.soinside.com 2019 - 2024. All rights reserved.