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

Swift泛型链表中如何自动适配类型执行相等性判断?

Swift泛型链表:自动适配引用/值类型的replaceOrAppend实现

你遇到的核心问题是===仅支持引用类型(AnyObject),而==要求类型遵循Equatable,直接写死判断逻辑会导致泛型约束冲突。要实现无额外约束、自动适配的逻辑,最优雅的方式是用Swift泛型条件重载,给LinkedList分别实现针对两种类型的方法版本,让编译器自动选择对应逻辑。

具体实现

第一步:补全链表基础方法

先确保链表具备append和insertBetween的正确实现(如果还未编写):

public class LinkedListNode<T> {
    init(value: T) {
        self.value = value
    }
    public var next: LinkedListNode?
    public weak var previous: LinkedListNode?
    public var value: T
}

struct LinkedList<T>: Sequence {
    internal var head: LinkedListNode<T>?
    internal unowned var tail: LinkedListNode<T>?

    // 原有的insert方法
    @discardableResult public mutating func insert(_ value: T, after: LinkedListNode<T>) -> LinkedListNode<T> {
        if after === tail {
            return append(value)
        } else {
            let node = LinkedListNode<T>(value: value)
            insertBetween(node, after: after, before: after.next)
            return node
        }
    }

    // 新增append方法
    @discardableResult public mutating func append(_ value: T) -> LinkedListNode<T> {
        let newNode = LinkedListNode(value: value)
        if let tailNode = tail {
            insertBetween(newNode, after: tailNode, before: tailNode.next)
        } else {
            head = newNode
        }
        tail = newNode
        return newNode
    }

    // 新增insertBetween辅助方法
    private mutating func insertBetween(_ node: LinkedListNode<T>, after: LinkedListNode<T>?, before: LinkedListNode<T>?) {
        node.previous = after
        node.next = before
        after?.next = node
        before?.previous = node
        if head == nil {
            head = node
        }
    }

    // 实现Sequence协议,支持first(where:)
    public func makeIterator() -> LinkedListIterator<T> {
        LinkedListIterator(current: head)
    }
}

// 链表迭代器实现
struct LinkedListIterator<T>: IteratorProtocol {
    var current: LinkedListNode<T>?

    mutating func next() -> LinkedListNode<T>? {
        let temp = current
        current = current?.next
        return temp
    }
}

第二步:添加条件重载的replaceOrAppend方法

通过扩展给LinkedList添加两个版本的replaceOrAppend,分别对应引用类型和值类型:

extension LinkedList {
    // 处理类对象:用===判断引用相等
    @discardableResult public mutating func replaceOrAppend(_ value: T) -> LinkedListNode<T> where T: AnyObject {
        if let existingNode = first(where: { $0.value === value }) {
            existingNode.value = value
            return existingNode
        } else {
            return append(value)
        }
    }

    // 处理值类型(Int、结构体等):用==判断内容相等
    @discardableResult public mutating func replaceOrAppend(_ value: T) -> LinkedListNode<T> where T: Equatable {
        if let existingNode = first(where: { $0.value == value }) {
            existingNode.value = value
            return existingNode
        } else {
            return append(value)
        }
    }

    // 兜底处理不支持的类型
    @discardableResult public mutating func replaceOrAppend(_ value: T) -> LinkedListNode<T> {
        fatalError("类型 \(T.self) 必须是类对象或遵循Equatable协议")
    }
}

为什么这样可行?

  • 当传入类对象时,编译器自动匹配where T: AnyObject的方法,用===做引用判断;
  • 当传入Int、String或自定义结构体(只要遵循Equatable),编译器会选择where T: Equatable的版本,用==做内容判断;
  • 如果传入既不是类也不遵循Equatable的类型,会直接抛出错误,避免无意义的操作。

使用示例

// 测试值类型
var intList = LinkedList<Int>()
intList.replaceOrAppend(5)
intList.replaceOrAppend(5) // 替换已有节点
print(intList.map { $0.value }) // 输出 [5]

// 测试引用类型
class User {
    var name: String
    init(name: String) { self.name = name }
}

var userList = LinkedList<User>()
let user1 = User(name: "Alice")
userList.replaceOrAppend(user1)
let user2 = User(name: "Alice")
userList.replaceOrAppend(user2) // 不同引用,追加新节点
print(userList.map { $0.value.name }) // 输出 ["Alice", "Alice"]

let user3 = user1
userList.replaceOrAppend(user3) // 相同引用,替换已有节点

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 18:20:34