【问题标题】:Swift extension with class: how to make a function to return an object's real type?带类的 Swift 扩展:如何使函数返回对象的真实类型?
【发布时间】:2022-01-05 03:01:14
【问题描述】:

我有这样的代码:

class A{}


class B: A{
    var val = 1
}

class C: A{
    var num = 5
}


extension Optional where Wrapped == [B?]{
    var vals: [B]{
        var result = [B]()
        if let arr = self{
            for part in arr{
                if let val = part{
                    result.append(val)
                }
            }
        }
        return result
    }
}

extension Optional where Wrapped == [C?]{
    var vals: [C]{
        var result = [C]()
        if let arr = self{
            for part in arr{
                if let val = part{
                    result.append(val)
                }
            }
        }
        return result
    }
}


var one: [B?]? = [B()]

var two: [C?]? = [C(), nil]



print(one.vals.count)
print(two.vals.count)

这是优化后的:

合二为一,用于 B(A 的子类)和 C(A 的子类)

extension Optional where Wrapped: Collection{
    var vals: [A]{
        var result = [A]()
        if let arr = self{
            for part in arr{
                if let val = part as? A{
                    result.append(val)
                }
            }
        }
        return result
    }
}

现在问题来了,

对于以下情况,

如何进行优化?

print(one.vals.first?.val ?? "")
print(two.vals.first?.num ?? "")

我猜,我需要一个函数来返回对象的真实类型

PS:我知道,要处理数据,结构与协议完美搭配

虽然这是一个公司项目,但我是新人

【问题讨论】:

    标签: swift class runtime


    【解决方案1】:

    只是为了好玩。将其保留为计算属性而不是通用方法的另一种可能方法是创建一个具有关联类型 WrappedAnyOptional 协议,并使其符合 Optional。然后你可以创建一个计算属性来返回其WrappedElementWrapped类型的数组:


    protocol AnyOptional {
        associatedtype Wrapped
        var optional: Optional<Wrapped> { get }
    }
    
    extension Optional: AnyOptional {
        var optional: Optional<Wrapped> { self }
    }
    
    extension AnyOptional where Wrapped: Sequence, Wrapped.Element: AnyOptional {
        var elements: [Wrapped.Element.Wrapped] {
            optional?.compactMap(\.optional) ?? []
        }
    }
    

    print(one.elements) // "[B]\n"
    print(two.elements) // "[C]\n"
    
    print(one.elements.first?.val ?? "")  // "1\n"
    print(two.elements.first?.num ?? "")  // "5\n"
    

    【讨论】:

      【解决方案2】:

      您需要引入一个额外的类型变量来说明扩展适用于Optionals,其中Wrapped.Element 是另一个Optional任何类型。您必须用另一个类型变量来表达“任何类型”部分,但是您不能在扩展的声明中添加这个类型变量(尽管这个特性是proposed),或者属性的声明。相反,您可以做的是使 vals 成为一个函数:

      func vals<T>() -> [T] where Wrapped.Element == T? {
          var result = [T]()
          if let arr = self{
              for part in arr{
                  if let val = part{
                      result.append(val)
                  }
              }
          }
          return result
      }
      

      请注意,这可以简化为:

      extension Optional where Wrapped: Sequence {
          func vals<T>() -> [T] where Wrapped.Element == T? {
              self?.compactMap { $0 } ?? []
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-12
        相关资源
        最近更新 更多