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
您需要引入一个额外的类型变量来表示扩展适用于 Optional
s,其中 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=] } ?? []
}
}
纯属娱乐。将其保留为计算 属性 而不是通用方法的另一种可能方法是创建具有关联类型 Wrapped
的 AnyOptional
协议并使其符合 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"
我有这样的代码:
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
您需要引入一个额外的类型变量来表示扩展适用于 Optional
s,其中 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=] } ?? []
}
}
纯属娱乐。将其保留为计算 属性 而不是通用方法的另一种可能方法是创建具有关联类型 Wrapped
的 AnyOptional
协议并使其符合 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"