简体   繁体   English

如何在 Swift 中为泛型类型添加类型方法?

[英]How to add type methods to generic types in Swift?

I am trying to add a type (aka static) method to a generic class in Swift.我正在尝试向 Swift 中的泛型类添加类型(又名静态)方法。 Here is the code.这是代码。

class StateArchive<T> {
    class func emptyAllArchives() {
        // do something
    }
}

// the compiler emits an error: "Argument for generic parameter 'T' could not be inferred"
StateArchive.emptyAllArchives()

I can get the above code to compile by providing the type in place of T like so:我可以通过提供类型代替 T 来编译上面的代码,如下所示:

StateArchive<AnyObject>.emptyAllArchives()

This looks awkward, however.然而,这看起来很尴尬。 Initially I though that the reason for this could be that one could create a class variable with type T. A quick test in the playground revealed that the compiler emits a message saying:最初我认为这样做的原因可能是人们可以创建一个类型为 T 的类变量。在操场上的一个快速测试显示编译器发出一条消息说:

"Class stored properties not yet supported in generic types". “泛型类型尚不支持类存储属性”。

Does anyone know how to create a type method in a generic type and let the client call this method without providing the type in place of T?有谁知道如何在泛型类型中创建类型方法并让客户端调用此方法而不提供类型来代替 T?

When encountering an issue with generics that doesn't work the way expect it's often useful, to help understand the issue, to think about what would happen if you replaced a placeholder with different concrete types.当遇到泛型问题无法正常工作时,它通常很有用,有助于理解问题,想想如果用不同的具体类型替换占位符会发生什么。

So for example, suppose you defined the following (this won't compile for the reason you give, but imagine it did):例如,假设您定义了以下内容(由于您给出的原因,这不会编译,但可以想象它确实如此):

class C<T> {
    static var a: [T] = []

    static func addElement(i: T) {
        a.append(i)
    }
}

Really, when you write class C<T> , you aren't writing a class.真的,当您编写class C<T> ,您并不是在编写类。 You're writing a blueprint for an infinite number of possible classes – C<Int> , C<String> , C<AnythingElse> .您正在为无数可能的类编写蓝图—— C<Int>C<String>C<AnythingElse>

Under these circumstances, suppose you wrote C.addElement(1) – so T would be Int .在这些情况下,假设您编写了C.addElement(1) – 所以T将是Int Then later, you wrote C.addElement("one") .后来,你写了C.addElement("one") Would Ca now contain one item, or two? Ca现在会包含一项还是两项? What would the type of a be? a的类型是什么?

Probably the most reasonable answer would be that there would be a C<Int>.a with one element, and a C<String>.a with one element.可能最合理的答案是有一个带有一个元素的C<Int>.a和一个带有一个元素的C<String>.a But this could get very confusing, and it doesn't seem like there are use cases to justify this kind of functionality.但这可能会变得非常混乱,而且似乎没有用例可以证明这种功能的合理性。

Generally, static methods and properties are best used rarely, and you may find you are better off with non-static members and methods, combined with a singleton pattern (or maybe not even that).通常,最好很少使用静态方法和属性,并且您可能会发现将非静态成员和方法与单例模式结合使用会更好(或者甚至可能不使用)。 If you still find the need for static-like functions, you may be better off using a generic free function (eg func emptyArchive<T: C>(c: C) { } ).如果您仍然发现需要类静态函数,则最好使用通用的自由函数(例如func emptyArchive<T: C>(c: C) { } )。

The other answer is correct in its explanations, but you can in fact get the behavior you intuitively expected with this:另一个答案在其解释中是正确的,但实际上您可以通过以下方式获得直观预期的行为:

extension StateArchive where T == Any {

    static func emptyAllArchives() {
        // do something
    }
}

// works as expected
StateArchive.emptyAllArchives()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM