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
相关产品推荐
相关产品推荐

