Swift class 扩展:如何为 return 对象的实际类型创建一个函数?

Swift extension with class: how to make a function to return an object's real type?

我有这样的代码:

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

我想,我需要一个函数来 return 对象的真实类型

PS: I know , to handle data , struct is perfect with protocol

While it's a company project, & I'm a new one

您需要引入一个额外的类型变量来表示扩展适用于 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 { [=11=] } ?? []
    }
}

纯属娱乐。将其保留为计算 属性 而不是通用方法的另一种可能方法是创建具有关联类型 WrappedAnyOptional 协议并使其符合 Optional 。然后你可以创建一个计算 属性 到 return 其 Wrapped Element Wrapped 类型的数组:


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"