我是一个快速的初学者。学习的时候有个困惑。现在我想定义一个抽象类或者定义一些纯虚方法,但是我找不到方法。我有一个关联类型的协议(protocol)(这个我也很纳闷,为什么不使用泛型协议(protocol)),有些方法需要在基类中实现,而其他继承自基类的类,他们应该在协议(protocol)中实现其他方法,我能怎么做? 例如:
Protocol P{
typealias TypeParam
func A()
func B()
}
class BaseClass<TypeParam> : P {
abstract func A()
func B(){
if someCondition {
A()
}
}
}
class ChildClass : BaseClass<Int> {
func A(){}
}
看起来很奇怪,我仍然找不到解决抽象问题的方法。
最佳答案
Swift 有类似的东西:协议(protocol)扩展
它们可以定义默认实现,因此您不必在基类中声明该方法,但它也不会强制在任何类、结构或枚举中执行此操作。
protocol P {
associatedtype TypeParameter
func A()
func B()
}
extension P {
func A(){}
}
class BaseClass<TypeParam> : P {
typealias TypeParameter = TypeParam
func B(){
if someCondition {
A()
}
}
}
class ChildClass : BaseClass<Int> {
// implementation of A() is not forced since it has a default implementation
func A(){}
}
另一种方法是使用协议(protocol)代替 BaseClass
更符合面向协议(protocol)的编程:
protocol Base {
associatedtype TypeParameter
func A()
func B()
}
extension Base {
func B(){
if someCondition {
A()
}
}
}
class ChildClass : Base {
typealias TypeParameter = Int
// implementation of A() is forced but B() is not forced
func A(){}
}
然而,最大的缺点之一是协议(protocol)类型的变量只能在泛型代码中使用(作为泛型约束):
var base: Base = ChildClass() // DISALLOWED in every scope
作为此限制的解决方法,您可以创建一个包装器类型:
// wrapper type
struct AnyBase<T>: Base {
typealias TypeParameter = T
let a: () -> ()
let b: () -> ()
init<B: Base>(_ base: B) where B.TypeParameter == T {
// methods are passed by reference and could lead to reference cycles
// below is a more sophisticated way to solve also this problem
a = base.A
b = base.B
}
func A() { a() }
func B() { b() }
}
// using the wrapper:
var base = AnyBase(ChildClass()) // is of type AnyBase<Int>
关于“真正的”泛型协议(protocol)的使用,Swift 团队选择使用 associatedtype
因为您可以使用许多泛型类型而不必全部写在括号中 <>
.
例如Collection
你在哪里有一个关联的 Iterator
和 Index
类型。这允许您拥有特定的迭代器(例如 Dictionary
和 Array
)。
一般来说,泛型/关联类型有利于编译期间的代码优化,但同时有时过于静态,您必须使用泛型包装器类型。
一些有用的链接 patterns for working with associated types .
(参见上文)
解决通过引用传递方法问题的更复杂的方法。
// same as `Base` but without any associated types
protocol _Base {
func A()
func B()
}
// used to store the concrete type
// or if possible let `Base` inherit from `_Base`
// (Note: `extension Base: _Base {}` is currently not possible)
struct BaseBox<B: Base>: _Base {
var base: B
init(_ b: B) { base = b}
func A() { base.A() }
func B() { base.B() }
}
struct AnyBase2<T>: Base {
typealias TypeParameter = T
var base: _Base
init<B: Base>(_ base: B) where B.TypeParameter == T {
self.base = BaseBox(base)
}
func A() { base.A() }
func B() { base.B() }
}
// using the wrapper:
var base2 = AnyBase2(ChildClass()) // is of type AnyBase2<Int>
关于swift 如何定义抽象类以及为什么苹果发明关联类型但不使用通用协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33098637/