使用 where 子句创建 Swift 扩展,该子句过滤采用泛型的结构

问题描述

我正在尝试在 Set 上创建一个使用 where 子句的扩展,以便它仅适用于我拥有的接受泛型的结构。但是我一直遇到关于它的错误,希望在结构中定义泛型

在此示例中,我收到以下错误,编译器提示建议我使用 <Any>对泛型类型“Test”的引用需要 <...>

struct Test<T> {
    var value : T
    func printIt() {
        print("value")
    }
}

extension Set where Element == Test {
    
}

但是,当我在结构中使用 <Any> 时,我收到此错误相同类型的约束类型“测试”不符合所需的协议“Equatable” >

extension Set where Element == Test<Any> {
    
}

关于如何让 where 子句接受我在泛型中使用的任何类型的测试结构的任何建议?

感谢您的帮助

解决方法

这是 Swift 类型系统的限制。没有具体的类型参数就无法谈论泛型类型,即使这些类型参数与类型的使用无关。对于这种特殊情况(所有可能的类型参数的扩展),我认为没有任何深层问题可以阻止它。它是 parameterized extensions 的一个更简单的版本,这是一个理想的功能。只是不支持 (though there is an implementation in progress)。

今天解决这个问题的标准方法是使用协议。

首先,进行一些与您的问题无关的清理工作(您可能已经知道了)。您的示例要求测试为 Hashable

struct Test<T: Hashable>: Hashable {
    var value : T
    func printIt() {
        print("value")
    }
}

制定一个协议,需要任何你想要的扩展部分,并使测试符合:

protocol PrintItable {
    func printIt()
}

extension Test: PrintItable {}

然后使用协议而不是类型:

extension Set where Element: PrintItable {
    func printAll() {
        for item in self { item.printIt() }
    }
}

let s: Set<Test<Int>> = [Test(value: 1)]

s.printAll()  // value

就您收到的错误消息再做一个说明。第一个错误,要求你添加 Any 实际上只是抱怨 Swift 不能谈论非参数化泛型,并在它不知道建议什么类型时建议它是后备类型:Any。

但是 Set<Any> 不是“任何类型的 Set”。它是一个 Set,其中 Element == Any。所以 Any 必须是可哈希的,这是不可能的。并且 Set<Int> 不是 Set<Any> 的子类型。有完全不同的类型。所以这些错误有点令人困惑,会让你走上一条毫无帮助的道路。

,

这是不可能的。 where 子句需要特定的数据类型,除非我指定更具体的内容,例如 Test,否则简单地传递 Test<String> 是行不通的。

感谢 Joakim 和 flanker 在评论中回答问题

,

如果您想使用 where 子句为 Set 添加扩展,您的测试必须确认Hashable 协议。 您的结构必须如下所示。

struct Test<T: Hashable> : Hashable {
    var value : T
    func printIt() {
        print("value")
    }
    func hash(into hasher: inout Hasher) {
        hasher.combine(value.hashValue)
    }
}

所以你不能使用Any作为你的扩展,你必须指定确认Hashable协议的类型.

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...