代码之家  ›  专栏  ›  技术社区  ›  John Montgomery

展开/合并多级可选

  •  4
  • John Montgomery  · 技术社区  · 7 年前

    我试着写一个函数来展开任意层数嵌套的可选项。下面是我正在使用的测试:

    let a: Int??? = 1
    let b: Int??? = nil
    print(a.unwrap(0), b.unwrap(0)) // should print 1, 0
    

    extension Optional {
        func unwrap<T> (_ defaultValue: T) -> T {
            return (self as? T) ?? defaultValue
        }
    }
    
    print(a.unwrap(0), b.unwrap(0)) // 1, 0
    

    但这并不妨碍使用与可选类型不同的类型调用函数。例如,我可以打电话 a.unwrap("foo") 它会打印“foo”而不是“1”,因为你当然不能施放 Int??? 到 String

    我试过用 Wrapped 相反,它会适当地限制默认值,但不会给出正确的输出:

    extension Optional {
        func unwrap (_ defaultValue: Wrapped) -> Wrapped {
            return (self as? Wrapped) ?? defaultValue
        }
    }
    
    print(a.unwrap(0), b.unwrap(0)) // Optional(Optional(1)), nil
    

    Int?? 它不返回默认值。

    1 回复  |  直到 7 年前
        1
  •  1
  •   ferranpujolcamins    7 年前

    此代码满足您的要求。 . 也许 吧 Sourcery

    protocol Unwrappable {
      associatedtype T
    
      func unwrap(_ default: T) -> T
    }
    
    extension Optional {}
    
    extension Optional: Unwrappable where Wrapped: Unwrappable {
      typealias T = Wrapped.T
    
      func unwrap(_ defaultValue: T) -> T {
        if let value = self {
          return value.unwrap(defaultValue)
        }
        return defaultValue
      }
    }
    
    extension Int: Unwrappable {
      typealias T = Int
    
      func unwrap(_ default: Int) -> Int {
        return self
      }
    }
    
    let nestedOptionalValue: Int??? = 6
    let nestedOptionalNil: Int??? = nil
    let optionalValue: Int? = 6
    let optionalNil: Int? = nil
    print(nestedOptionalValue.unwrap(0)) // prints 6
    print(nestedOptionalNil.unwrap(0))   // prints 0
    print(optionalValue.unwrap(0))       // prints 6
    print(optionalNil.unwrap(0))         // prints 0
    

    诀窍在于,Unwrappable协议标记了最终可以展开(如在0、1或更多展开之后)为特定类型的类型。

    这个问题的困难在于,在Optional的扩展中,可以获得Wrapped类型,但是如果Wrapped再次是Optional,则无法访问Wrapped.Wrapped(换句话说,Swift不支持更高种类的类型)。

    Optional where Wrapped == Optional . 但是您需要更高类型的支持来访问Wrapped.Wrapped类型。如果我们试图扩展 Optional where Wrapped == Optional<T>

    推荐文章