Как развернуть необязательное значение из любого типа?

Учитывая массив из [Any] который имеет сочетание необязательных и необязательных значений, например:

 let int:Int? = 1 let str:String? = "foo" let values:[Any] = [int,2,str,"bar"] 

Как мы можем извлечь значение Optional в Any типе (если оно есть), чтобы мы могли создать общую функцию печати, которая выводит только значения.

Например, эта функция printArray проходит и печатает каждый элемент:

 func printArray(values:[Any]) { for i in 0..<values.count { println("value[\(i)] = \(values[i])") } } printArray(values) 

Что будет выводить:

 value[0] = Optional(1) value[1] = 2 value[2] = Optional("foo") value[3] = bar 

Как мы можем изменить его, чтобы он печатал только базовое значение, чтобы оно разворачивало значение, если оно необязательно? например:

 value[0] = 1 value[1] = 2 value[2] = foo value[3] = bar 

Обновление прогресса …

Он может работать при изменении аргумента на [Any?] , Например:

 let values:[Any?] = [int,2,str,"bar"] func printArray(values:[Any?]) { for i in 0..<values.count { println("value[\(i)] = \(values[i]!)") } } printArray(values) 

Который напечатает желаемое:

 value[0] = 1 value[1] = 2 value[2] = foo value[3] = bar 

Но хотелось бы посмотреть, как мы можем развернуть необязательный MirrorType.value Any поскольку это возвращает MirrorType.value что затрудняет извлечение необязательного значения, например:

 class Person { var id:Int = 1 var name:String? } var person = Person() person.name = "foo" var mt:MirrorType = reflect(person) for i in 0 ..< mt.count { let (name, pt) = mt[i] println("\(name) = \(pt.value)") } 

Распечатывает:

 id = 1 name = Optional("foo") 

Когда мне нужно:

 id = 1 name = foo 

Для Xcode 7 и Swift 2:

 func unwrap(any:Any) -> Any { let mi = Mirror(reflecting: any) if mi.displayStyle != .Optional { return any } if mi.children.count == 0 { return NSNull() } let (_, some) = mi.children.first! return some } let int:Int? = 1 let str:String? = "foo" let null:Any? = nil let values:[Any] = [unwrap(int),2,unwrap(str),"bar", unwrap(null)] 

Это даст вам [1, 2, "foo", "bar", {NSObject}]

Измените NSNull() на nil и возвращаемое значение unraw func на Any? всегда будет разворачивать любой тип.

Чтобы проверить, является ли какая- Any переменная опциональной, протокол может использоваться как средство безличного Необязательного .

Точно так же, как его в настоящее время невозможно (как и для Swift 2), чтобы проверить на отсутствие Необязательный Необязательно, также не представляется возможным превратить в необязательный вариант:

 let anyType: Any.Type = Optional.self let anyThing: Any = Optional.Some("string") anyType is Optional.Type // Causes error let maybeString = anything as? Optional // Also causes error // Argument for generic parameter 'Wrapped' could not be inferred 

Однако предлагаемый OptionalProtocol также может использоваться для предоставления универсального интерфейса для доступа к необязательным значениям и даже разворачивания их:

 protocol OptionalProtocol { func isSome() -> Bool func unwrap() -> Any } extension Optional : OptionalProtocol { func isSome() -> Bool { switch self { case .None: return false case .Some: return true } } func unwrap() -> Any { switch self { // If a nil is unwrapped it will crash! case .None: preconditionFailure("nill unwrap") case .Some(let unwrapped): return unwrapped } } } // With this we can check if we have an optional let maybeString: String? = "maybe" let justString: String = "just" maybeString is OptionalProtocol // true justString is OptionalProtocol // false 

Благодаря предоставленным методам опциональные опции могут быть проверены и доступны совершенно естественным образом, без необходимости невозможного добавления в Optional :

 let values:[Any] = [ Optional.Some(12), 2, Optional.None, // a "wrapped" nil for completeness Optional.Some("maybe"), "something" ] for any in values { if let optional = any as? OptionalProtocol { if optional.isSome() { print(optional.unwrap()) } else { // nil should not be unwrapped! print(optional) } continue } print(any) } 

Что будет печатать:

 12 2 nil maybe something 

Я думаю, что это своего рода ошибка.

В общем, чтобы обнаружить и извлечь конкретный тип из Any , down casting с as единственный поддерживаемый метод. Но :

 let int:Int? = 1 let any:Any = int switch any { case let val as Optional: // < [!] cannot downcast from 'Any' to a more optional type 'Optional' print(val) default: break } 

Это означает, что для этого нет поддерживаемого способа.

В любом случае, видимо, вы можете сделать это с reflect :

 func printArray(values:[Any]) { for i in 0.. 0 && ref[0].0 == "Some" { // replace `val` with unwrapped value val = ref[0].1.value; ref = reflect(val) } println("value[\(i)] = \(val)") } } let int:Int? = 1 let str:String? = "foo" let values:[Any] = [int,2,str,"bar"] printArray(values) 

выходы:

 value[0] = 1 value[1] = 2 value[2] = foo value[3] = bar 

ДОБАВЛЕНО: небольшая измененная версия

 func printArray(values:[Any]) { for i in 0.. 0 && ref[0].0 == "Some" { // Drill down to the Mirror of unwrapped value ref = ref[0].1 } let val = ref.value println("value[\(i)] = \(val)") } } 

Факторинг в функцию:

 func unwrapAny(val:Any) -> Any { var ref = reflect(val) while ref.disposition == .Optional && ref.count > 0 && ref[0].0 == "Some" { ref = ref[0].1 } return ref.value } func printArray(values:[Any]) { for i in 0.. 

Чтобы, возможно, спасти кого-то от вымотания всего этого из ответов и комментариев, вот ответ, включающий как «нормальные» способы, так и некоторые, что я считаю улучшением для Swift 3, идущего с Xcode 8.2.1.

Использование отражения

 func unwrap(_ any: T) -> Any { let mirror = Mirror(reflecting: any) guard mirror.displayStyle == .optional, let first = mirror.children.first else { return any } return first.value } 

обсуждение

Принятый ответ от bubuxu не скомпилирован с Swift 3. Поскольку в его комментарии предлагается строка поиска, изменение .Optional .optional исправляет это (см. SE-0005 и Swift API Design Guidelines ).

Причины я думал, что это решение может быть улучшено:

  • Я нахожу возrotation NSNull() странным.
  • Я думаю, что альтернатива возвращать nil с возвращаемым типом Any? также проблематично, потому что он превращает все (включая необязательные значения) в необязательные значения (например, unwrap(any: 42) возвращает Optional(42) ).
  • При вызове unwrap(any:) с чем-либо, кроме значения Any (более того, кто-нибудь?) Компилятор Swift 3 предупреждает о неявном принуждении к Any .

Для ответа Саджона применимы сходные мысли.

Решение, которое я предлагаю, касается всех этих вопросов. Имейте в виду, что unwrap(_:) возвращает nil как тип Any поэтому использование оператора объединения nil больше не работает. Это означает, что это просто смещается вокруг того, что, по моему мнению, проблематично во втором вопросе. Но я нашел, что это было правильное решение для (для меня) более интересного варианта использования рефлексии.

Использование расширения по выбору

 protocol OptionalProtocol { func isSome() -> Bool func unwrap() -> Any } extension Optional : OptionalProtocol { func isSome() -> Bool { switch self { case .none: return false case .some: return true } } func unwrap() -> Any { switch self { case .none: preconditionFailure("trying to unwrap nil") case .some(let unwrapped): return unwrapped } } } func unwrapUsingProtocol(_ any: T) -> Any { guard let optional = any as? OptionalProtocol, optional.isSome() else { return any } return optional.unwrap() } 

обсуждение

Это базовое решение LopSae, обновленное до Swift 3. Я также изменил сообщение об unwrapUsingProtocol(_:) предварительного условия и добавил unwrapUsingProtocol(_:) .

Применение

 class Person { var id:Int = 1 var name:String? } var person = Person() person.name = "foo" let mirror = Mirror(reflecting: person) for child in mirror.children.filter({ $0.label != nil }) { print("\(child.label!) = \(unwrap(child.value))") } 

Независимо от того, используете ли вы unwrapUsingProtocol() или unwrapUsingProtocol() , это будет печатать

 id = 1 name = foo 

Если вы ищете способ аккуратно выровнять выходные данные, см. Как использовать вкладки для равномерного выделения строк описания в Swift?

Небольшое изменение на @thm, чтобы полностью развернуть:

 func unwrap(_ any: T) -> Any { let mirror = Mirror(reflecting: any) guard mirror.displayStyle == .optional, let first = mirror.children.first else { return any } return unwrap(first.value) } 

Не полный ответ. Это сводится к следующему:

 let int:Int? = 1 let str:String? = "foo" let values:[Any] = [int,2,str,"bar"] func printArray(values:[Any]) { for i in 0.. 

как насчет этого решения, я сделал общую версию предыдущего ответа.

 fileprivate func unwrap(value: Any) -> (unwraped:T?, isOriginalType:Bool) { let mirror = Mirror(reflecting: value) let isOrgType = mirror.subjectType == Optional.self if mirror.displayStyle != .optional { return (value as? T, isOrgType) } guard let firstChild = mirror.children.first else { return (nil, isOrgType) } return (firstChild.value as? T, isOrgType) } let value: [Int]? = [0] let value2: [Int]? = nil let anyValue: Any = value let anyValue2: Any = value2 let unwrappedResult:([Int]?, Bool) = unwrap(value: anyValue) // ({[0]}, .1 true) let unwrappedResult2:([Int]?, Bool) = unwrap(value: anyValue2) // (nil, .1 true) let unwrappedResult3:([UInt]?, Bool) = unwrap(value: anyValue) // (nil, .1 false) let unwrappedResult4:([NSNumber]?, Bool) = unwrap(value: anyValue) ({[0]}, .1 false) 

Ниже приведен код на игровой площадке.

введите описание изображения здесь

Не делая этого слишком сложным, почему бы и нет:

 let int:Int? = 1 let str:String? = "foo" let values:[Any?] = [int,2,str,"bar"] for var i:Int = 0; i < values.count; i++ { println("\(values[i]!)") } 

Это печатает:

1
2
Foo
бар

Основываясь на решении @bubuxu, можно также:

 func unwrap(any: T) -> T? { let mirror = Mirror(reflecting: any) guard mirror.displayStyle == .optional else { return any } guard let child = mirror.children.first else { return nil } return unwrap(any: child.value) as? T } 

Но вам нужно проверять нуль, используя ?? nil ?? nil при использовании unwrap , как это сделано в foo

 func foo(_ maybeValue: T?) { if let value: T = unwrap(any: maybeValue) ?? nil { print(value) } } 

Тем не менее, аккуратно!

( Кто-нибудь получил решение для проверки? )

В соответствии с примерами использования шаблонов перечислений в Swift 2.0 они могут выглядеть следующим образом:

 let pattern :[Int?] = [nil, 332, 232,nil,55] for case let number? in pattern { print(number) } 

Выход: 332, 232, 55

  • Вызов метода фабрики Swift с использованием точечной нотации?
  • Каков самый чистый способ применения map () для словаря в Swift?
  • Swift Alamofire: как получить код статуса ответа HTTP
  • Ошибка компилятора: метод с селектором Objective-C конфликтует с предыдущим объявлением с тем же селектором Objective-C
  • Когда мне нужно быстро получить доступ к свойствам с помощью self?
  • Как создать вертикальное меню прокрутки в spritekit?
  • Почему имя аргумента shorthand $ 0 возвращает кортеж всех параметров?
  • Объект X classа Y не реализует методSignatureForSelector в Swift
  • Быстрые переменные украшения с надписью «?» (Вопросительный знак) и «!» (Восклицательный знак)
  • .toInt () удален в Swift 2?
  • Swift - Пользовательский сеттер на свойстве
  • Interesting Posts

    Найти все прошлые IP-адреса рабочего стола

    DT И DT Обрабатывают NA в x непоследовательно

    Возвращаемое значение из функции $ .ajax ()

    Как реализовать перетаскиваемую вкладку с помощью Java Swing?

    Медленное шифрование и дешифрование AES GCM с помощью Java 8u20

    Сервер WWW сообщает об ошибке после запроса POST через интернет Прямые компоненты в Delphi

    Поддерживает ли устройство, поддерживающее USB 3.0, компьютер, поддерживающий USB 2.0

    Существуют ли библиотеки функций нечеткого поиска или строковых функций сходства для C #?

    Добавьте разделитель тысяч в число с Javascript или jQuery?

    .htaccess для определения языка

    Функция tellg () дает неправильный размер файла?

    Как нарисовать интерактивную полилинию на маршруте google maps v2 android

    Каким детерминированным является неточность с плавающей запятой?

    Стандартное отклонение в LINQ

    Внедрение неуправляемой dll в управляемую C # dll

    Давайте будем гением компьютера.