Swift 3引入了AnyHashable
,这是Hashable周围的类型擦除框。它解决了当协议需要关联类型时如何存储符合相同协议的不同类型对象的问题。
创建AnyHashable
框时,您必须在初始化程序中提供要包装的内容:
let someHashable: AnyHashable = AnyHashable(1)
但是,您也可以使用AnyHashable,就像使用协议而不实际创建任何内容一样。这就好像Apple重载了赋值运算符来进行自动装箱:
let someHashable: AnyHashable = 1
我的问题是,这怎么可能?我已经在网上关注了几个关于如何创建我自己的类型擦除框的指南。 https://www.bignerdranch.com/blog/breaking-down-type-erasures-in-swift/ 然而,似乎Apple正在采用其他方式进行其他工作。
如果它只是一个类型擦除的盒子,你仍然需要在某处提供类型,如下所示:
class MyClass<T> where T: Hashable {
let someHashable: AnyHashable<T>
}
否则编译器会抱怨:"requires arguments in <...>"
。
但我可以简单地创建一个变量:
let someHashable: AnyHashable
我问,因为我正在实现一个使用关联类型的委托。我为它创建了一个类型擦除的盒子,但是我想隐藏下面有类型擦除的事实(类似于AnyHashable
似乎工作的方式)。
这是我的实现(暂时忽略weak
属性的要求)。
// The delegate protocol
public protocol SomeDelegate {
associatedtype T
func doSomething(_ t: T)
}
// Type-erasure boilerplate
fileprivate class _AnySomeDelegateBase<T>: SomeDelegate {
init() {
guard type(of: self) != _AnySomeDelegateBase.self else {
fatalError("Must subclass")
}
}
func doSomething(_ t: T) {
fatalError("Must override")
}
}
fileprivate final class _AnySomeDelegateBox<SD: SomeDelegate> : _AnySomeDelegateBase<SD.T> {
private var concrete: SD
init(_ concrete: SD) {
self.concrete = concrete
}
override func doSomething(_ t: T) {
self.concrete.doSomething(t)
}
}
// Type-erasure wrapper
public final class AnySomeDelegate<T>: SomeDelegate {
private let box: _AnySomeDelegateBase<T>
public init<SD: SomeDelegate>(_ base: SD) where SD.T == T {
self.box = _AnySomeDelegateBox(base)
}
public func doSomething(_ t: T) {
self.box.doSomething(t)
}
}
以下是我想用它的方法:
class MyViewController: UIViewController {
var delegate: AnySomeDelegate?
}
但这不起作用:AnySomeDelegate requires arguments in <...>
。这意味着我还必须参数化UIViewController
T
周围的class MyViewController<T>: UIViewController {
var delegate: AnySomeDelegate<T>?
}
。
[mysqld]
#...
#UTF8 stuff
skip-character-set-client-handshake
collation-server=latin1_general_ci
character-set-server=latin1