Swift中如何定义元素为遵循Equatable协议的泛型类型数组?
解决Swift中混合泛型类型数组的问题
你遇到的核心问题是:File<T: Equatable>是一个泛型类,当你用不同的T(比如String、Int)实例化它时,得到的是完全不同的具体类型(File<String>和File<Int>不是同一个类型),所以Swift不允许直接把它们放在同一个[File]数组里——因为File本身是泛型,必须指定具体的类型参数。
正确解决方案:用非泛型协议抽象公共行为
我们可以定义一个非泛型的协议,提取Folder需要用到的File的公共属性和方法,让所有File<T>实例都遵循这个协议,这样就能把它们存入同一个协议类型的数组中。
步骤1:定义非泛型协议
protocol FileProtocol { var visible: Bool { get set } // 提供当前行的字符串描述,满足你拼接输出的需求 var currentLineDescription: String { get } }
步骤2:让File<T>遵循协议
修改你的File类,实现协议要求的属性:
class File<T: Equatable>: FileProtocol { var lines = [T]() var lineCursor: Int = 0 var currentLine: T { get { return lines[lineCursor] } set { lineCursor = lines.index(where: { $0 == newValue }) ?? 0 } } var visible = true // 实现协议的属性,把泛型的currentLine转成字符串描述 var currentLineDescription: String { return String(describing: currentLine) } }
步骤3:修改Folder的数组类型
把files的类型改成[FileProtocol],这样就能容纳任何遵循该协议的File<T>实例:
class Folder { var files = [FileProtocol]() func currentLinesFromVisibleFiles() -> String { return files.filter({ $0.visible }) .map({ $0.currentLineDescription }) .joined(separator: "/") } }
测试代码
现在你的测试代码可以正常运行,输出期望的"string/489/true":
var stringFile = File<String>() stringFile.lines = ["strong", "string", "a", "b", "c"] stringFile.currentLine = "string" stringFile.visible = true var intFile = File<Int>() intFile.lines = [6, 12, 0, 489] intFile.currentLine = 489 intFile.visible = true var doubleFile = File<Double>() doubleFile.lines = [92.12, 4.9753, 1.6] doubleFile.currentLine = 92.12 doubleFile.visible = false var boolFile = File<Bool>() boolFile.lines = [true, false] boolFile.currentLine = true boolFile.visible = true var folder = Folder() folder.files = [stringFile, intFile, doubleFile, boolFile] let output = folder.currentLinesFromVisibleFiles() print(output) // 输出:"string/489/true"
为什么你之前的尝试都失败了?
[File<Any>]:Any没有遵循Equatable协议,不符合File<T>的泛型约束[File<Any & Equatable>]:Swift不允许把带有Self关联类型的协议(比如Equatable)当作具体类型使用,Any & Equatable无法作为合法的泛型参数- 其他写法要么是语法错误(比如
[File<Any: Equatable>]),要么是传入了不符合约束的类型(比如元组类型不遵循Equatable)
内容的提问来源于stack exchange,提问作者Rudy Phillipps
相关产品推荐
相关产品推荐

