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

Swift结构体中实现可选递归类型的可行方案求助

解决Swift递归结构体的Codable实现问题

方案一:使用包装类(Box)实现递归引用

Swift结构体是值类型,编译时需确定内存大小,直接递归引用会导致内存计算失败。通过引入通用包装类Box,可以间接实现递归引用,同时完全兼容Codable协议:

// 通用包装类,用于封装递归类型
final class Box<T>: Codable where T: Codable {
    let value: T
    init(_ value: T) {
        self.value = value
    }
}

struct PostType: Hashable, Codable {
    let _id: String
    let content: String
    let time: Int
    let comments: Int
    let loves: Int
    let reposts: Int
    let poster: Poster
    let revisions: [Revision]
    let edited: Int?
    let repost: Box<PostType>? // 用Box包装实现递归
}

// 示例依赖类型,需遵循Codable协议
struct Poster: Hashable, Codable {
    let id: String
    let name: String
}

struct Revision: Hashable, Codable {
    let time: Int
    let content: String
}

使用时通过post.repost?.value访问递归内容即可,编解码过程完全透明——Box会自动将内部值序列化为与原PostType一致的JSON结构,解码时也能正确还原。

方案二:将PostType改为类(Class)

若业务场景允许放弃值语义,将PostType改为类是更直接的方案。类作为引用类型,编译时仅需存储指针大小,不存在递归内存计算问题:

class PostType: Hashable, Codable {
    let _id: String
    let content: String
    let time: Int
    let comments: Int
    let loves: Int
    let reposts: Int
    let poster: Poster
    let revisions: [Revision]
    let edited: Int?
    let repost: PostType?

    // 实现Hashable协议
    static func == (lhs: PostType, rhs: PostType) -> Bool {
        return lhs._id == rhs._id
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(_id)
    }

    // 自定义初始化器
    init(_id: String, content: String, time: Int, comments: Int, loves: Int, reposts: Int, poster: Poster, revisions: [Revision], edited: Int?, repost: PostType?) {
        self._id = _id
        self.content = content
        self.time = time
        self.comments = comments
        self.loves = loves
        self.reposts = reposts
        self.poster = poster
        self.revisions = revisions
        self.edited = edited
        self.repost = repost
    }
}

// 示例依赖类型
struct Poster: Hashable, Codable {
    let id: String
    let name: String
}

struct Revision: Hashable, Codable {
    let time: Int
    let content: String
}

该方案无需额外包装,直接支持repost: PostType?,但需注意类的引用语义与结构体的值语义差异,需结合业务场景判断是否适用。

方案三:使用indirect枚举包装递归部分

若想保留结构体特性,也可通过indirect枚举封装递归内容,同样满足Codable要求:

indirect enum PostContainer: Codable {
    case post(PostType)
}

struct PostType: Hashable, Codable {
    let _id: String
    let content: String
    let time: Int
    let comments: Int
    let loves: Int
    let reposts: Int
    let poster: Poster
    let revisions: [Revision]
    let edited: Int?
    let repost: PostContainer?
}

// 示例依赖类型
struct Poster: Hashable, Codable {
    let id: String
    let name: String
}

struct Revision: Hashable, Codable {
    let time: Int
    let content: String
}

使用时通过case let .post(post)取出内部的PostType,该方案虽稍显繁琐,但能在保留结构体值语义的同时实现递归。

以上三种方案均满足支持JSON解码、遵循Codable协议、repost为可选类型的要求,可根据业务需求选择适配方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 11:43:11