Swift泛型类型约束报错:表达式类型歧义,求解决方案
问题原因
当前MultiSpecifications的泛型设计要求数组中的所有元素必须是同一具体类型的Specification实现,但你传入的SizeSpecification和ColorSpecification是两个不同的结构体类型。Swift无法为泛型参数Spec推断出一个统一的类型,因此抛出类型歧义错误。
解决方案
有两种可行的修复方式,根据你的Swift版本选择:
方案一:使用类型擦除(兼容所有Swift版本)
创建一个类型擦除结构体,将不同的Specification实现包装为统一类型,让MultiSpecifications可以接受混合类型的规格数组。
步骤1:添加类型擦除结构体
struct AnySpecification<T>: Specification { private let _isSatisfied: (T) -> Bool init<S: Specification>(_ specification: S) where S.T == T { _isSatisfied = specification.isSatisfied } func isSatisfied(item: T) -> Bool { return _isSatisfied(item) } }
步骤2:修改MultiSpecifications定义
struct MultiSpecifications<T>: Specification { let listOfSpecifications: [AnySpecification<T>] func isSatisfied(item: T) -> Bool { listOfSpecifications.allSatisfy { $0.isSatisfied(item: item) } } }
步骤3:正确实例化MultiSpecifications
将每个规格包装为AnySpecification:
let multiSpecs = MultiSpecifications<Product>(listOfSpecifications: [ AnySpecification(SizeSpecification(sizeToFilter: .large)), AnySpecification(ColorSpecification(colorToFilter: .blue)) ])
方案二:使用存在类型(Swift 5.7+)
Swift 5.7引入了存在类型any,可以直接声明数组包含任意符合Specification<T>的类型,无需额外的类型擦除。
步骤1:修改MultiSpecifications定义
struct MultiSpecifications<T>: Specification { let listOfSpecifications: [any Specification<T>] func isSatisfied(item: T) -> Bool { listOfSpecifications.allSatisfy { $0.isSatisfied(item: item) } } }
步骤2:直接实例化MultiSpecifications
无需包装,直接传入不同类型的规格:
let multiSpecs = MultiSpecifications<Product>(listOfSpecifications: [ SizeSpecification(sizeToFilter: .large), ColorSpecification(colorToFilter: .blue) ])
补充:修复实例化遗漏
原代码中betterFilter未实例化,需要添加:
let betterFilter = BetterFilter()
完整可运行代码示例(以方案二为例)
enum Color { case red, green, blue } enum Size { case small, medium, large } struct Product { let name: String let color: Color let size: Size } protocol Specification { associatedtype T func isSatisfied(item: T) -> Bool } protocol Filtering { associatedtype T func filter<S: Specification>(in items: [T], with specification: S) -> [T] where S.T == T } struct BetterFilter: Filtering { typealias T = Product func filter<S>(in items: [Product], with specification: S) -> [Product] where S : Specification, Product == S.T { items.filter { specification.isSatisfied(item: $0) } } } struct ColorSpecification: Specification { typealias T = Product let colorToFilter: Color func isSatisfied(item: Product) -> Bool { item.color == colorToFilter } } struct SizeSpecification: Specification { typealias T = Product let sizeToFilter: Size func isSatisfied(item: Product) -> Bool { item.size == sizeToFilter } } struct MultiSpecifications<T>: Specification { let listOfSpecifications: [any Specification<T>] func isSatisfied(item: T) -> Bool { listOfSpecifications.allSatisfy { $0.isSatisfied(item: item) } } } // 运行代码 let apple = Product(name: "Apple", color: .red, size: .small) let banana = Product(name: "Banana", color: .green, size: .large) let bmwCar = Product(name: "BMW", color: .blue, size: .large) let laptop = Product(name: "Dell laptop", color: .blue, size: .large) let allProducts: [Product] = [apple, banana, bmwCar, laptop] let multiSpecs = MultiSpecifications<Product>(listOfSpecifications: [ SizeSpecification(sizeToFilter: .large), ColorSpecification(colorToFilter: .blue) ]) let betterFilter = BetterFilter() let results = betterFilter.filter(in: allProducts, with: multiSpecs) // 输出结果:["BMW", "Dell laptop"] print(results.map { $0.name })
内容的提问来源于stack exchange,提问作者Aaron Phan
相关产品推荐
相关产品推荐

