简体   繁体   English

Swift从泛型类型继承

[英]Swift Inherit from Generic Type

I'm trying to inherit from a generic type, so that I can insert a type into a hierarchy: 我试图从泛型类型继承,以便我可以在层次结构中插入一个类型:

class Foo < T:AnyObject > : T {}

but I get error 但我得到错误

inheritance from non-protocol, non-class type 'T'

but I'm ensuring T is a class (even if I change AnyObject to some other class). 但我确保T是一个类(即使我将AnyObject更改为其他类)。 Is this just not possible? 这不可能吗?

You can't inherit from something if you don't know what it is, for multiple reasons. 出于多种原因,如果您不知道它是什么,则不能继承。

  • For one, the compiler needs to know how to lay out an instance of your class in memory. 首先,编译器需要知道如何在内存中布置类的实例。 To do that, it needs to know what instance variables (stored properties) it has: both those the class specifies and those inherited from a superclass. 要做到这一点,它需要知道它具有哪些实例变量(存储属性):类指定的那些和从超类继承的那些。

  • The compiler also needs to know about the superclass' properties and initializers to make sure that an instance of your class is properly initialized. 编译器还需要了解超类的属性和初始化程序,以确保正确初始化类的实例。 If the superclass' properties are unknown, there's no way to know if you've initialized all the state that you should (and none that you shouldn't) before your initializer ends. 如果超类的属性是未知的,那么在初始化程序结束之前,无法知道您是否已初始化了应该进行的所有状态(并且没有一个你不应该这样做)。 If the superclass' initializers are unknown, the compiler can't enforce that you call a superclass' designated initializer from your own. 如果超类的初始化程序未知,则编译器无法强制您从自己的程序中调用超类'指定的初始化程序。

  • How will you write method implementations that reference properties and methods of the superclass if you don't know what the superclass is? 如果您不知道超类是什么,您将如何编写引用超类属性和方法的方法实现? If you write code that references self.view , then somehow instantiate a version of your class that doesn't inherit from a class with that property, that code would break. 如果编写引用self.view代码,那么以某种方式实例化一个不从具有该属性的类继承的类的版本,该代码将中断。

There are probably several more reasons, but these should be enough. 可能还有几个原因,但这些原因应该足够了。 :) :)

Though there are a few places where you're expected to subclass, Cocoa (whether in Swift or ObjC) generally favors composition instead of inheritance for customization. 虽然有一些地方需要你进行子类化,但Cocoa(无论是在Swift还是ObjC中)通常都倾向于使用组合而不是继承来进行自定义。

If you're adding a bunch of functionality to various view controllers, and reusing the code for such by factoring it out into its own class, the simple solution is to make your view controller classes all own an instance of that class instead of trying to be that class. 如果您要向各种视图控制器添加一堆功能,并通过将其分解到自己的类中来重用代码,那么简单的解决方案就是让您的视图控制器类都拥有该类的实例而不是尝试那个班级。 If you have places where you want to enforce that certain view controller classes must own a Foo , you can define a protocol that expresses that requirement. 如果您希望强制执行某些视图控制器类必须拥有Foo ,则可以定义表示该要求的协议。

If you're trying to add functionality to an existing class, you can use an extension. 如果您尝试向现有类添加功能,则可以使用扩展名。 You might not be able to use an extension to add stored properties, but you can certainly fake it. 您可能无法使用扩展来添加存储的属性,但您当然可以伪造它。 For example, you could use computed properties, and define your own storage within their implementation. 例如,您可以使用计算属性,并在其实现中定义您自己的存储。 One way to do that might be to use the associated objects feature of the ObjC runtime (which AFAIK is still accessible from Swift). 一种方法可能是使用ObjC运行时的关联对象功能 (仍然可以从Swift访问AFAIK)。

Isn't CRTP ( Curiously recurring template pattern ) different than in the OP anyways? CRTP( 奇怪的重复模板模式 )是否与OP不同?

It's totally fine to design that pattern in Swift (<= 3.0), but it's currently bugged and will lock on initialization without any error during runtime. 在Swift(<= 3.0)中设计该模式是完全没问题的,但它目前存在漏洞,并且会在运行时锁定初始化而不会出现任何错误。

class Template<T> { ... }

class RealThing : Template<RealThing> { ... }

I recently discovered this pattern in bridged UIKit API. 我最近在桥接的UIKit API中发现了这种模式。 You can read that in my short blog post here . 你可以阅读,在我短暂的博客文章在这里

I also translated the example from wiki into Swift 3.0: 我还将示例从wiki翻译成Swift 3.0:

protocol Constructor {
    init()
}

protocol Shape {
    func cloned() -> Shape
}

typealias ShapeProtocols = Constructor & Shape

class Shape_CRTP<T> : ShapeProtocols {

    required init() {}

    func  cloned() -> Shape {
        let new = Shape_CRTP<T>()
        // copy everything to `new` from `self`
        return new
    }
}

extension Shape_CRTP where T : ShapeProtocols {

    func cloned() -> Shape {
        let new = T()
        // copy everything to `new` from `self`
        return new
    }
}

// First non-crtp proof of concept
class Square : ShapeProtocols {

    required init() {}
    func cloned() -> Shape {
        return Square()
    }
}

let clone = Shape_CRTP<Square>().cloned() // creates a new `Shape`
type(of: clone) // Square.Type

// now CRTP but this is bugged: http://blog.devandartist.com/posts/swift-crtp
class Circle : Shape_CRTP<Circle> {}

Circle().cloned()

print("this will never print because of the described bug")

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

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