Swift Type-Erased(类型擦除)

ReyZhang ReyZhang 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区

前言

泛型编程对现代软件开发有着不可忽视的作用,我们希望在 protocol 中加入 associated types ,但是令人不愉快的是编译器似乎总是闹别扭。 在 swift 中 类型擦除 是一种不错地将 associated types 转化为 generic constraints 的方法。

面向协议的编程在 swift 中是非常提倡的对吧? 我的意思是甚至是在 WWDC 会议期间,人们呐喊出:"Protocols are awesome!"。他们让你定义接口,允许你忽略那些接口的实现。在 Swift 的世界中,如果我们将协议称之为国王,那么泛型则可以视作皇后,所谓一山不容二虎,当我们把这两者结合起来使用的时候,似乎会遇到极大的困难。那么是否有一种方法,能够将这两个概念结合在一起,以便让它们成为我们前进道路上的垫脚石,而不是碍手碍脚的呢?答案是有的,这里我们将会使用到类型擦除 (Type Erasure) 这个强大的特性。

具体类型与抽象类型

当你开始学习一门编程语言的时候,你很有可能是从 string、int 或者 float 开始学习的:这些都是所谓的「具体类型 (concrete type)」,也就是编译器能够在编译时确定此类型所占的空间大小——这使得编译器对具体类型的处理非常友好。如果某个类型可以被初始化——也就是说您可以调用它的初始化方法——那么就说明它是一个具体类型。

另外一种类型就是「抽象类型 (abstract type)」( 也被称为存在类型 (existential) )。对于抽象类型来说,编译器无法知道这个类型的确切功能。当编译器处理抽象类型的时候,它无法知晓其所占的空间大小;甚至可能会认为这个类型是不存在的。事实上,您很可能见到过这样的错误描述「我无法为您找寻到此类型」。

在 Swift 当中,抽象类型的普遍表述方式使用 associatedType 来描述的,之前我们是使用typealias来定义的,此外泛型 <T> 同样也是一个抽象类型。如果编译器无法在编译时知晓类型的所占空间大小,或者您无法将其初始化,也就是说您没办法调用它的 init 的方法:那么就说明这个类型很可能是抽象类型。

什么是 Swift 中的类型擦除?

有很多地方会用到类型擦除,并且它们的作用的各不相同。在 Java 当中,它用来让编译器知晓其相关内容,它会抹除 的存在,然后用一个具体类型将其替代。在 Swift 当中,我们不必处理这些琐事,我们可以自行实现——有很多您可以选择的实现方式。对于类型擦除来说,绝大多数语言当中的基本概念是相同的,但是在 Swift 当中,它解决了这个问题。

遇到的问题

假设我们简单的定义一个口袋妖怪的协议:

protocol Pokemon {
    associatedtype Power //每个口袋妖怪都有自己的属性 但是属性是一个抽象的类 (可以是🔥 ⚡️...)
    func attack() -> Power //攻击
}

//电属性的皮卡丘
struct Pikachu: Pokemon {
    func attack() -> 🌩 {
        return 🌩()
    }
}

//火属性的喷火龙
struct Charmander: Pokemon {
    func attack() -> 🔥 {
        return 🔥()
    }
}

// 属性类型
struct 🔥 { }
struct 🌩 { }

看起来好像没啥问题,接下来我们开始让口袋妖怪攻击吧,

let pokemon: Pokemon = Pikachu()
pokemon.attack()

Oh,No 编译器报错了!

在这里插入图片描述

注意: 如果一个协议中使用了associatedtype 关联类型,那么在调用时就不能再使用这个协议来指明变量类型,反之是可以的。

解决办法

这时候就需要 类型擦除 了,我们想用一个抽象的Pokemon 类型 来代替 Pikachu 类型:

struct AnyPokemon<Power>: Pokemon {
    
    // 我们需要保存 properties 和 functions
    // Pokemon protocol 将会用到
    private let _attack: () -> Power
    
    init<P: Pokemon where P.Power == Power>(_ pokemon: P) {
        _attack = pokemon.attack
    }
    
    func attack() -> Power {
        // using the original Pokemon's attack implementation
        return _attack()
    }
}
 
let firePowerPokemon = AnyPokemon<🔥>(Charmander())
// 现在我们丢失了喷火龙的属性信息
// firePowerPokemon 可以是任何火属性的口袋妖怪
firePowerPokemon.attack() //🔥

解决方法升级

现在还有一个更简单的方式来解决associated types的问题:

struct AnyPokemon<P: Pokemon>: Pokemon {
    
    private let pokemon: P
    
    init(_ pokemon: P) {
        self.pokemon = pokemon
    }
    
    func attack() -> P.Power {
        return pokemon.attack()
    }
}
 
// 使用
let pokemon = AnyPokemon(Pikachu())
pokemon.attack()

但很可惜,这不是 类型擦除 。

参考文章地址:

https://realm.io/news/altconf-hector-matos-type-erasure-magic/
http://krakendev.io/blog/generic-protocols-and-their-shortcomings

...全文

相关推荐

【信息科学与工程学】计算机科学与自动化——第二十四篇 编译器10——编译原理与词法分析02

链接时优化:全局DCE(579)、LTO(580)安全编译:CFI(581、586)、ASan(582)、UBSan(583)、MSan(584)、TSan(585)、CET(587)、PAC(588)、MTE(589)、SFI(590)、Wasm沙箱(591)侧信道与秘密:侧信道缓解(592)、常量时间(593)、秘密清理(594)内存安全:ASLR(595)、栈保护(596)、整数溢出检测(597)、除零检测(598)、空指针检测(599)、数组边界检查(600)至此编号达到600。

flyair_China

windows窗口界面的单机4人麻将游戏源码

除了普通打牌外还包括听牌考验,打牌时还能设置为明打、用户玩家默打、委托给程序等。

实在不行了吗

基于双闭环控制的反激式Flyback开关电源闭环仿真设计【仿真+文献+Mathcad计算书】

内容概要:本文围绕“基于双闭环控制的反激式Flyback开关电源闭环仿真设计”展开,提供了完整的仿真模型、技术文献及Mathcad计算书等资源。核心内容涵盖反激式开关电源的基本工作原理、双闭环控制系统(通常包含电压环和电流环)的设计与实现方法,以及利用仿真工具对其动态响应、系统稳定性、负载调整率等关键性能指标进行全面验证。文档不仅详细展示了电路参数的设计计算过程,还特别强调了理论分析与工程实践的紧密结合,适用于从事开关电源研发的技术人员进行深入学习与项目复现。; 适合人群:具备电力电子技术基础,熟悉开关电源基本原理,且拥有一定仿真软件操作经验的电气工程、自动化及相关专业的研究生、科研人员和工程师。; 使用场景及目标:① 掌握反激式开关电源双闭环控制系统的完整设计流程与工程实现细节;② 学习并实践基于仿真工具的电源系统建模、参数扫描及性能分析方法;③ 通过配套的Mathcad计算书深入理解关键设计参数的理论推导与计算依据,有效提升独立设计与优化能力。; 阅读建议:建议读者结合所提供的仿真文件、技术文献和Mathcad计算书进行系统性学习,首先理解整体设计思路与架构,然后逐步剖析各个功能模块的实现原理,并亲自动手操作仿真以验证和深化对理论分析的理解,从而达到理论与实践融会贯通的学习目标。

大龙不吃小鱼干

YOLO26算法室内手持遥控器目标检测+训练好的模型+111张数据集+pyqt可视化界面.zip

附训练好的 YOLO 权重与 PyQt 可视化检测界面,页面底部含可视化效果预览,毕设/课设开箱即用。 【数据集概况】 · 检测类别(中文):[遥控器(remote)] · 训练集:105 张 · 验证集:4 张 · 测试集:2 张 · 总计:111 张 该数据集聚焦于室内环境中手持遥控器的精准识别,旨在为智能家居系统、家电控制终端及人机交互设备提供高质量的视觉检测基础。通过覆盖多种握持角度与拍摄姿态,数据集有效模拟了真实用户操作场景,具备高度实用价值。... 【训练曲线与评估图】 【模型训练配置】 参数 | 值 模型 | yolo26n 训练轮数 | 100 epochs 输入尺寸 | 640x640 批次大小 | 24 优化器 | auto 初始学习率 | 0.01 训练设备 【关键指标汇总】 训练了 60 个 epoch,最终轮指标: 指标 | 数值 mAP50 | **0.9950** mAP50-95 | 0.7089 Precision | 0.9860 Recall | 1.0000 train/box_loss | 0.8613 train/cls_loss | 0.4944 val/box_loss | 1.2640 val/cls_loss | 0.4215 【训练过程分析】 我从头到尾盯着了 60 轮的训练曲线。前 30 轮,loss 情况是先快后慢。初期,模型似乎对识别遥控器这种特定物体有了飞快的反应,box_loss 跳水式地下降,从 1.2 下降到 0.9,然后 cls_loss 也快速收敛。不过,过了 30 轮,loss 曲线开始变得平滑,不再有显著波动,整体都保持在较低的水平,特别是 box_loss 没有出现明显的平台期或反弹现象。这说明模型在前半程对目标定位准确,且收敛... 使用场景:毕业设计、课程设计、深度学习入门、工业场景落地验证。

guo_xiao_xiao_

基于PSO-DWA无人机三维动态避障路径规划研究(Matlab代码实现)

内容概要:本文研究了基于粒子群优化算法(PSO)与动态窗口法(DWA)相结合的无人机三维动态避障路径规划方法,并提供了Matlab代码实现。该方法利用PSO进行全局路径优化,以搜索从起点到目标点的最优路径,同时结合DWA实现局部动态避障,使无人机能够在飞行过程中实时规避静态或移动障碍物。通过融合两种算法的优势,不仅提升了路径规划的全局寻优能力,还增强了对复杂动态环境的适应性与响应速度。文中系统阐述了算法的设计原理、实现流程以及在三维空间中的仿真验证过程,充分展示了该方法在复杂场景下的有效性、鲁棒性及工程应用潜力。; 适合人群:具备一定MATLAB编程基础,从事无人机导航、智能优化算法、路径规划及相关领域的科研人员、研究生及工程技术人员。; 使用场景及目标:①应用于无人机在城市空域、灾害救援、智能巡检等复杂动态环境下的自主导航与实时避障任务;②为智能交通系统、移动机器人、无人车等领域的路径规划问题提供先进的算法参考与技术支持;③支持科研工作者复现、改进PSO-DWA混合算法,推动智能路径规划领域的创新研究与实践应用。; 阅读建议:建议读者结合提供的Matlab代码进行动手实践,按照文档结构逐步学习算法原理与实现细节,重点关注PSO与DWA的协同机制、参数配置策略及三维仿真环境的构建方法,深入理解算法在动态避障中的决策逻辑,以便更好地掌握其核心技术并应用于实际科研与工程项目中。

科研_G.E.M.
评论
收藏 已收藏
分享
返回顶部
ReyZhang
ReyZhang 新星创作者: 移动开发技术领域 新星创作者: 移动开发技术领域
Rey的移动开发社区 420 成员 23 内容