ios - 使包装器将自我类型化为自我的扩展
问题描述
对不起,奇怪的标题。这是我的代码的玩具草图:
extension UIControl {
func makeHolder() -> ControlHolder {
ControlHolder(control: self)
}
}
struct ControlHolder {
let control : UIControl
init(control: UIControl) {
self.control = control
}
func retrieve() -> UIControl {
return self.control
}
}
我承认这是一个玩具还原,我不喜欢人们这样做,但它完美地说明了句法问题,所以让我们继续吧。
好的,所以我们在 UIControl 上有一个扩展,它是一个返回包装器对象的方法。现在,问题是这样的:
let holder = UISwitch().makeHolder()
let output = holder.retrieve()
结果output
, 显然是作为 UIControl 输入的。但这不是我想要的。我希望它输入为 UISwitch,因为我从 UISwitch 开始。好的,所以这听起来像一个通用的。问题是,我不知道如何使它通用。
我认为,使 ControlHolder 成为泛型很容易:
struct ControlHolder<T:UIControl> {
let control : T
init(control: T) {
self.control = control
}
func retrieve() -> T {
return self.control
}
}
我很确定我的那部分是正确的。但是,我该如何编写扩展声明,以便将泛型解析为实际类型,即调用self
UIControl的类型?makeHolder
我尝试在扩展中引入泛型,服从编译器,直到我编译它:
extension UIControl {
func makeHolder<T>() -> ControlHolder<T> {
ControlHolder<T>(control: self as! T)
}
}
但这很愚蠢,并且output
仍然输入为 UIControl。
显然,我可以添加另一个参数,将类型显式传递给makeHolder
并解决它:
extension UIControl {
func makeHolder<T>(ofType: T.Type) -> ControlHolder<T> {
ControlHolder<T>(control: self as! T)
}
}
现在,当我打电话时,makeHolder
我传入了类型:
let holder = UISwitch().makeHolder(ofType: UISwitch.self)
let output = holder.retrieve()
现在当然output
是输入为 UISwitch。但这是愚蠢的!我希望扩展只知道类型是 UISwitch,因为我正在调用makeHolder
UISwitch。
我觉得我在这一切都错了。也许有人可以纠正我?还是我的目标是不可能的事情?
解决方案
这样做的诀窍是定义一个协议,该协议的扩展,并将该makeHolder
方法放入该扩展中。这样,您可以将Self
其用作返回的泛型类型ControlHolder
。
首先定义一个新协议(我们称之为“ HoldableControl
”)并要求conformers必须是UIControl
s。它不需要任何其他要求,因为我们只关心将makeHolder
功能添加到扩展中。
protocol HoldableControl: UIControl {}
然后,在其中添加一个扩展名HoldableControl
和定义makeHolder
,返回ControlHolder<Self>
. 我们可以在Self
这里使用,因为它在协议扩展中是允许的,不像在UIControl
.
extension HoldableControl {
func makeHolder() -> ControlHolder<Self> {
ControlHolder(control: self)
}
}
然后,我们只需要UIControl
符合这个协议:
extension UIControl: HoldableControl {}
ControlHolder
并像您已经完成的那样使您的通用:
struct ControlHolder<T: UIControl> {
let control: T
init(control: T) {
self.control = control
}
func retrieve() -> T {
control
}
}
现在它将起作用:
let holder = UISwitch().makeHolder() // type is ControlHolder<UISwitch>
let output = holder.retrieve() // type is UISwitch
推荐阅读
- python - 如何使用 datetime 模块在 Python 中组合两次?
- python - 使用网络图绘制时间选择器
- kotlin - 等待 3 秒 Kotlin
- azure - 无法将 golang 应用部署到 Azure 应用服务容器
- java - ImageAnalysis 用例 CameraX 人脸检测
- html - vite 无法处理 xxx.html 文件
- visual-studio-code - 扩展主机意外终止(vscode - reactjs)
- java - 普罗米修斯没有显示正确的结果
- mysql - 更新命令在 MySql 工作台中不起作用
- android - 模拟器:警告:崩溃服务未启动模拟器:错误:在内核映像文件中找不到“Linux 版本”字符串: