You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何针对遵循IDable协议的可选数组扩展通用方法?

问题与解决方案

问题场景

首先定义以下结构体:

struct Screw: Codable {
    let id: String
    // 其他属性
}
struct Nail: Codable {
    let id: String
    // 其他属性
}

struct Parts: Codable {
    var screws: [Screw]?
    var nails: [Nail]?
}

为Optional<[Screw]>编写扩展后可以正常调用:

extension Optional {
    mutating func blah() where Wrapped == [Screw] {
        if self == nil { self = [] }
        if self!.count > 13 && self![13].id == "666" { self?.remove(at: 13) }
    }
}

// 调用正常
stuff.parts.screws.blah()

但定义IDable协议并让结构体遵循后,尝试编写通用扩展时编译报错:

protocol IDable {
    var id: Int { get }
}

struct Screw: Codable, IDable {
    let id: Int
    // 其他属性
}
struct Nail: Codable, IDable {
    let id: Int
    // 其他属性
}

// 错误的扩展写法
extension Optional {
    mutating func blah() where Wrapped == [IDable] {
        // 逻辑代码
    }
}

// 调用时报错:Instance method 'blah()' requires the types '[Screw]' and '[any IDable]' be equivalent
stuff.parts.screws.blah()

可行实现方式

问题根源在于[Screw](具体类型数组)和[any IDable](存在类型数组)并非同一类型,无法通过Wrapped == [IDable]的约束匹配。正确的做法是通过泛型约束,让扩展适用于所有元素遵循IDable的可替换集合:

extension Optional where Wrapped: RangeReplaceableCollection, Wrapped.Element: IDable {
    mutating func blah() {
        // 初始化空集合(如果当前是nil)
        if self == nil {
            self = Wrapped()
        }
        guard let collection = self, collection.count > 13 else {
            return
        }
        // 获取第14个元素(下标13)
        let targetIndex = collection.index(collection.startIndex, offsetBy: 13)
        if collection[targetIndex].id == 666 {
            self?.remove(at: targetIndex)
        }
    }
}

说明

  • RangeReplaceableCollection协议提供了init()(创建空集合)和remove(at:)方法,刚好匹配原逻辑的需求;
  • 通过Wrapped.Element: IDable约束,确保集合中的元素都拥有id属性;
  • 这种写法不仅支持[Screw]和[Nail],还支持其他遵循RangeReplaceableCollection且元素符合IDable的类型。

如果只需要针对数组优化,可以将约束更具体:

extension Optional where Wrapped == Array<Element>, Element: IDable {
    mutating func blah() {
        if self == nil { self = [] }
        guard let count = self?.count, count > 13 else { return }
        if self![13].id == 666 {
            self?.remove(at: 13)
        }
    }
}

内容的提问来源于stack exchange,提问作者Fattie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 03:57:24