Определите, если Any.Type является необязательным

Я пытаюсь определить, является ли данный тип t (Any.Type) является необязательным типом, я использую этот тест

t is Optional<Any>.Type

но он всегда возвращает ложь.

Так есть ли способ добиться этого?

6 ответов

Решение

Предполагая, что вы пытаетесь сделать что-то вроде этого:

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

Немного опоздал на вечеринку. Но я столкнулся с той же проблемой. Вот мой код

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

Опции соответствуютExpressibleByNilLiteral, так что вы можете использовать это:

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

Вы можете сделать что-то вроде этого:

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)))

Или если вам нужно преобразовать из Any в Optional

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

Ты можешь сделать:

      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

Вы можете использовать дженерики для достижения этой цели:

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",

Я понимаю, что сравнение строк не является удобным способом сделать эту проверку, я попытаюсь снова найти что-то более производительное..

Другие вопросы по тегам