代码之家  ›  专栏  ›  技术社区  ›  Benjohn

扩展到泛型结构,其中元素是泛型结构

  •  0
  • Benjohn  · 技术社区  · 5 年前

    FutureValue<Element> Failable<Element> ,两者都实现 map

    struct FutureValue<Element> {
       func map<U>(_ t: (Element) -> U) -> FutureValue<U> …
    }
    
    struct Failable<Element> {
       func map<U>(_ t: (Element) -> U) -> Failable<U> …
    }
    

    我想在上面写一个扩展名 FutureValue Element Failable ,以便实现 地图 类似于映射到 元素 FutureValue<Failable<Element>>

    我怎么能用斯威夫特?

    1 回复  |  直到 5 年前
        1
  •  4
  •   Rob Napier    5 年前

    你只需要创建一个协议来捕获“任何故障”,并捕获你想要的算法片段。

    protocol AnyFailable {
        associatedtype Element
        func map<U>(_ t: (Element) -> U) -> Failable<U>
    }
    

    并表示所有故障都是可故障的。

    extension Failable: AnyFailable {}
    

    您可能希望在协议上添加方法以提取所需的数据或提供方法。

    然后,创建扩展:

    extension FutureValue where Element: AnyFailable {
        func map<U>(_ t: (Element.Element) -> U) -> FutureValue<Failable<U>> {
            // You will probably need to provide your own implementation here
            return FutureValue<Failable<U>>(element: element.map(t))
        }
    }
    

    值得注意的是我是如何构建这个的。我开始写一个更具体的形式基于 String (随便挑一件):

    extension FutureValue where Element == Failable<String> {
        func map<U>(_ t: (String) -> U) -> FutureValue<Failable<U>> {
            ...
        }
    }
    

    我写了一段简单的消费代码:

    let f = FutureValue(element: Failable(element: "alice"))
    print(f.map { $0.first })
    

        2
  •  1
  •   Benjohn    5 年前

    非常感谢罗伯的帮助 super answer

    我在最后采取的方法略有不同,所以我把它作为第二个答案。对于一个泛型的扩展受到某种元素的约束的情况,我觉得这种方法更简单。它也是一种很容易引入的“模式”,可以很容易地应用到类似的情况中。

    /* 
     Protocol for things that can be _concretely_ represented as a `Failable`.
     I keep it private so it's just used to constrain the protocol extension
     below.
    */
    private protocol AsFailable {
        associatedtype Element
        var asFailable: Failable<Element> {get}
    }
    
    /*
     `Failable` can definitely be represented `AsFailable`…
    */
    extension Failable: AsFailable {
        var asFailable: Failable<Element> {
            return self
        }
    }
    
    /*
     Use the `AsFailable` protocol to constrain an extension to `FutureValue`
     for any `FutureValue` who's `Element` is a `Failable`.
    */
    extension FutureValue where Element: AsFailable {    
        func happyMap<U>(_ t: @escaping (Element.Element) -> U) 
        -> FutureValue<Failable<U>>  {
            return map { $0.asFailable.map(t) }
        }
    }
    
    

    map (如OP中所述),但当我想实施时,我开始挣扎 flatMap AsFailable 让我快速编写一个 平面图

    我认为 AsXXX 这种方法对于这样一个需要协议的情况来说是简单的 只是 需要作为约束。

    这是什么 happyFlatMap

    func happyFlatMap<U>(_ t: @escaping (FailableElement) -> FutureValue<Failable<U>>)
        -> FutureValue<Failable<U>>
    {
        typealias Out = FutureValue<Failable<U>>
        return flatMap {
            failable in
            switch failable.asFailable {
    
            case let .happy(element):
                return t(element)
    
            case let .error(error):
                return Out(Failable<U>.error(error))
    
            case let .canceled(reason):
                return Out(Failable<U>.canceled(reason))
            }
        }
    }