Tag: 通用编程

使用协议掌握泛型:规范模式

如果您正在阅读本文,那么您很可能已经知道使用泛型的好处。 您想要减少编码。 您希望编写的代码能做更多。 您以前曾尝试在编程中使用泛型,但有可能使您从未想到的挫败感达到顶点。 你不是一个人。 能够以一种通用的方式工作,但是仍然可以成功地推断出您的类型可能很棘手。 幸运的是,将泛型与协议的使用结合起来确实很有效,而且一旦您学习了少量技术,您就会发现这棘手的事情实际上并不是那么棘手。 为了探讨该主题,我们将构建和完善一个针对以下四个方面的规范设计模式: (我希望)这些技术将成为您的编码库中的主要内容。 顺便说一句,这种模式是解决开放-封闭原则的极好方法。 我强烈建议您熟悉的东西,以及我最近 在这里 写的一些东西 。 过滤产品 我们的假设情况是,我们有一个称为Product的实体,并且我们希望能够按某种规格过滤一系列产品。 首先让我们看一下Product : 这是有道理的,因为我们的协议类型Specification是泛型的,而且我们可以可行地添加一个规范实例,该实例的关联类型不是Product 。 我们需要做的是检查items参数中的类型是否与spec参数中的类型相同。 让我们尝试一下。 技术2:检查通用实例上的条件 我们可以使用以下模式在函数声明的开头执行检查: func someFunc (参数:T)其中T.someProperty == self.someProperty 请注意,我们在输入参数之前使用了典型的占位符语法 ,以表明我们的函数正在使用泛型类型。 为了能够访问T实例的内部,我们需要首先说一下实例的类型是 ; 在这种情况下, T的类型为SomeType 。 接下来,我们需要表明我们要检查使用where关键字完成的条件。 最后,我们可以访问T.someProperty类型的属性并执行布尔检查。 现在,只要通用类型为SomeType且其值someProperty与我们自己的类型相匹配,该函数就可以使用。 考虑到这一点,让我们构建一个通用过滤器 ,该过滤器可以在规范associatedtype与物料类型匹配的情况下接受任何物料和任何规格。 现在,代替将specs参数类型设置为Specification ,我们可以改用Spec,因为它具有与我们Filter (第5行) 中的那个相关联的关联类型 ,这是安全的。 创建协议后,实现Filter本身非常简单。 我们遵循协议(第9行),设置类型别名 (第10行),然后filter(items:,specs 🙂神奇地将其自身设置为正确的类型。 现在,我们可以使用我们先前制作的Product实例进行测试 在这一点上,我们可以肯定地说一切正常。 使用我们当前的设计,创建更多的过滤器和规格是一项非常简单的任务。 但是,让我们看看是否可以进一步完善它。 目前,我们的ColorSpecification实体仅适用于Product类型的实例。 […]

在Swift中使用泛型的13个理由

我决定使用电视节目“ 为什么要使用13种理由 ”撰写一篇有关仿制药的文章,以说明我们如何使用它们,希望您会喜欢! 提醒 Swift中的泛型是为项目编写“泛型”代码的一种方式:是的,但是还有什么呢? 这些通用类型可以用项目中可用的任何其他类型替换,也可以由Swift标准库提供。 它们通常用于创建结构,类或函数。 如果需要,泛型可以受协议约束 ,从而可以更精确地了解泛型。 您已经遇到的最常见的通用类型是Optional 。 您可以使用任何类型并将其设置为Optional,它将起作用。 这是因为Optional使用通用类型(在其定义中声明为Wrapped ),该通用类型允许您在其中放入任何内容。 而且,它可以有选择地帮助您编写更少 , 干净和可重用的代码! 让我们看看如何说明它们的用法。 语境 自由高中的新来学生汉娜·贝克尔 ( Hanna Becker)在未知的情况下自杀身亡。 她的朋友克莱·詹森 ( Clay Jensen)想知道她死亡的所有真相。 在她去世之前,她记录了13个原因 她用录音带传送给她的朋友托尼帕迪拉(Tony Padilla) 。 我们将尝试帮助克莱聆听录音带,并使用基本的Swift泛型原理最终认识他的朋友汉娜的真相。 不用担心,本文没有任何破坏 ! 帮助克莱·詹森 汉娜去世前,克莱曾 在他去学校的路上听音乐。 他拥有一个音乐播放器 ,该音乐播放器可以从CD和USB等多种支持中读取内容。 不幸的是,他的音乐播放器坏了。 由于我们是好人,我们将帮助他让它再次发挥作用。 我们将定义一个枚举AudioType ,它将包含不同类型的可能的支持。 我们还定义了一个名为AudioContent的协议,该协议将保存不同音频支持的属性 : 最后,真相 托尼刚把录音带交给了克莱: Tape类再次符合AudioContent协议,并且还具有title属性。 不幸的是,克莱无法用他的音乐播放器来读取磁带。 每个磁带都有不同的类型,是唯一的,并且由不同的属性组成: 这些自定义磁带是从Tape类继承的 ,因此它们也符合AudioContent协议。 请注意,它们可能还具有一些属性和方法。 克莱决定窃取能够读取任何磁带的托尼帕迪拉的磁带播放器 。 […]

在Swift中定义许多相同的结构

假设您希望定义一系列看起来相同的结构。 例如: 并且假设您要避免代码重复 。 如果您使用的是类,则可以使它们成为同一类的所有子类 。 但是有充分的理由避免在Swift中使用子类。 特别是它们在通用协议一致性方面表现不佳,这是我完全避免在我的大多数代码中完全避免它们的一个原因。 您可以尝试使它们全部符合特定协议 ,但不能通过协议扩展添加存储的属性或初始化程序(可以添加初始化程序,但它需要调用另一个必需的初始化程序)。 这是一个不错的解决方案,并且为复杂的代码库提供了一个出奇的灵活解决方案:使用特定的类型参数将它们全部变成相同的通用结构,即使这些类型参数是空结构: 这些说明符类型称为“幻像类型”,它们出奇的强大。 这个想法也适用于更复杂的场景。 在下面的示例中, x和y的类型变为通用类型,并且为每个结构分配了不同的静态名称。 或者,您可以使Unit成为Specifier本身的关联类型🙂

PHP仍缺少位:泛型。

本文是有关PHP缺失位的系列文章的第一篇。 以后的文章将讨论其他类型的概念,例如访问器和数据类型。 PHP 7.2即将来临,带来了与类型相关的更改,例如签名中的object类型或参数类型扩展。 这些证实了PHP社区加强PHP类型系统并提高类型安全性的意愿。 在Libcast,我们赞赏这些更改,这些更改使您可以依靠IDE在键入时显示类型错误,并在编译时验证类型,从而减少了查找和修复错误所需的时间 。 我们希望泛型是一项功能,希望不久后可以使用PHP,并允许使用给定类型的泛型容器。 泛型 泛型类允许声明必须在使用时专用的泛型容器 (您不能直接使用泛型类)。 任何类型都可以专用于泛型类,只要它们尊重泛型类中使用的签名即可。 泛型类可以使用几种泛型类型,然后仅通过修复泛型类型的子集来进行部分专业化 。 PHP中的泛型 RFC正在草拟中,但尚未被接受。 黑客/ HHVM 已经采用的泛型。 ircmaxell在PHP用户环境中进行了一个有趣的实验(当然,请勿在产品中使用此功能)。 泛型在PHP中对于容器非常有用:抽象数据类型(堆栈,队列,地图等)和域容器(日期集,一组人等)。 它们还将允许更精确的签名:目前,PHP可以iterable地在签名中声明集合,但是通用声明iterable可以使我们仅要求书本集合。 Libcast的仿制药案例 我们创建了一个Libcast新安全视频平台API的模拟模型,在该模型中,我们需要随机生成数据,但有时需要遵循给定的分发方式。 例如,我们想要生成每个具有给定机会被发射的域事件,从而在模拟中生成真实的数据 。 我们还希望根据当前访客群的真实地理分布来模拟假访客。 我们看到了一个机会,可以根据普通类中的分布来提取做出选择的部分。 这是处理引用的示例的简化的第一枪: //生成IP地址 最终课程IpGenerator { 公共函数generate(string $ countryCode =’FR’):IP { // … } } 最后一个类DistributedIpGenerator { / ** @var IpGenerator * / 私人发电机 / ** @var数组* / 私人$发行; […]

全面理解快速下标(第2部分)

因此,在本部分中,我将对带下标的示例进行更多说明。如果您错过了该部分,则为第1部分…… 介绍 : 下标只是从struct,class或enum中的列表或序列访问元素的快捷方式。 字典中的下标: 在字典中,当我们通过索引Index检索数据时。 在这种情况下,词典始终会抛出可选值。 由于该词典中不存在所需的密钥。 喜欢 : let simpleDictonaray = [“ Apple”:100,“ Orange”:130,“ Banana”:90] simpleDictonaray [“ Apple”] // 可选(100) 这个Dictionary抛出了optional(100),所以我们可以通过我们自己的下标来解决这个问题: 在这里,我们创建一个具有信息并具有下标的结构。 下标主体具有绑定临时变量newValue的值。如果info [key]具有值,则返回或返回0 正在访问: 这次, 今天的购物将不会提供可选的值。因为在其下标正文中,我们已经安全地展开了。 如果此实例没有所需的键,它将简单地返回0。 通用下标: 泛型下标与基本无异。只是类型是遗传类型。 如果我们用它创建实例并通过第三个括号访问,它将以基本下标的形式给出结果,如.. 下标中的多参数: 下标可以采用多个参数并进行计算,例如: 实例: 数组: 在Swift Array中实际上是一个通用的Struct。 其中有一个下标,为什么我们可以通过第三个括号访问元素?这是一个示例: 在这里,我们使用struct Array及其类型String来创建实例数组。然后在其上分配两个名称,并通过第三个括号[]来访问元素。CosArray Struct在swift库中的下标中具有以下内容: 公共下标(索引:Int)->元素 在Swift Array中,String Int和所有其他基本数据类型实际上是在struct中构建的。 保持摇摆不忘与朋友分享给我启发。

使用面向协议的编程进行通用JSON解析

澄清 : Codable,本文是关于实现可与Codable或您可能选择的任何东西一起使用的体系结构的 每个(Swift)软件开发人员最终都将需要为其iOS应用程序(或macOS)解析JSON。 在我的整个职业生涯中,我已经看到了许多关于如何解析JSON的体系结构方法。 您应该经常问自己(开发的任何功能): 您构建的体系结构是否是一种演化系统,可以在不修改基础代码/类/结构的情况下适应任何给定的更改( 如果不是,则不敏捷 ) 。 如果您的方法基于OOP,您是否保持SOLID原则不变? 服务是否为松耦合? 在最近的一次聚会中,我也参加了有关体系结构方法和原理的会议,他们展示了一张带有引号的幻灯片: 开发人员知道可以做什么。 应该做的。 那么应该怎么做……? 让我们分解一下JSON解析,即解析JSON涉及的内容: 调用一个请求到服务器并从闭包中获得响应 (例如)。 在大多数项目中,服务器端以不同的合法性响应我们的请求,因此,我们需要一个验证器来验证JSON响应的合法性,而不管我们需要解析的实际数据如何。 4xx我们可以验证JSON,否则,我们将返回错误。 解析 JSON并反序列化相关对象 从验证器 返回相关错误 。 没什么新鲜的,简单明了的🙂 我们的主要目标是编写一个小型且集中的代码,以分离上述所有步骤,并且当然要使用POP方式( 面向协议的编程 )。 我是Alamofire的忠实拥护者,因此我们假设响应是标准的DataResponse : Alamofire.request(…)。responseJSON {(resp:DataResponse )in …} 我们需要一个协议,该协议将描述我们先前细分的方法集。 我们将需要3种方法: 封装运行整个“显示”的实际逻辑的方法。 验证JSON的方法-此方法将返回内部JSON(稍后将显示一个示例)。 一种将解析我们的数据并创建实际对象的方法,该对象应该位于内部JSON内部。 公共协议ParseProtocol { ? ? )-> 吗? 扩展ParseProtocol { ? } 那返回类型呢? 由于方法begin将封装“整个”逻辑,因此它应该返回我们解析的对象以及一个Error类型,然后返回一个元组如何: func begin(forResponse响应:DataResponse […]

NSFetchedResultsController不想被模拟

更具体地说,NSFetchedResultsController的Objective-C泛型不能很好地与Swift协议的relatedtype配合使用。 “测试工程”背后的思想是,不是针对具体类的接口编写代码,而是针对具有相同接口且具体类遵循的协议编写代码。 对于“真实”构建,使用真实对象。 为了进行测试,可以替换模拟对象或伪造对象,从而进行可靠的测试。 对于基于Core-Data的应用程序,这意味着创建一个我们要针对其进行编码的“ NSFetchedResultsControllerPrototol”。 NSFetchedResultsController实际上有一个使用的泛型类-它的原始定义为NSFetchedResultsController : NSObject where ResultType: NSFetchedRequestResult 。 这对我们来说是完美的,因为这样我们可以使用关联的类型,然后用模拟代替所出售的对象。 在写出该方法时,不会产生任何内联错误,并且在进行规划和开发的前提下,这是可行的。 但是,到了构建的时候,结果却截然不同: 编译期间的分段错误意味着编译器本身已崩溃。 不幸的是,使用泛型时经常发生这种情况,短期内别无选择,只能解决。 (但是在此之前,警告是一团糟,错误看上去像表情符号,说明它们如何使您感觉:’_’,等)。 iOS的核心功能仍然是本机Objective-C,即使以Swift表示,也要等到验证尽可能接近您的特定用例后,才能假设它会起作用。 仍然可以模拟核心数据,包括健壮的模拟; 随后的文章将对其进行探讨。 编辑:现在归档为 Open Radar 35110402 。

Swift 1中的核心数据:创建纯Swift NSFetchedResultsControllerDelegate

在Swift中使用Core Data的路径不像高速公路,而更像是一条依山傍水的危险小径。 但是,像许多Swift问题一样,问题不是新的危险,而是现有的不安全做法正在被揭示。 一种方法是简单地重新创建不安全的做法,例如使用隐式展开的可选方法。 另一种方法是将所有内容包装在“ guard”和“ if let”的多个级别中,以使控制流隐藏在不必要的分支中。 无论如何,Objective-C的假设在框架中构建得越深,在与众不同的Swift世界中就越难使用。 即使系统已试图弥合差距,例如将具有混合结果的Objective-C泛型添加到NSFetchedResultsController中,这也是正确的。 编译器崩溃后,需要另一种方法。 与许多Cocoa委托一样,在Swift中使用NSFetchedResultsController的可能性受到它所施加的要求的限制:委托必须是NSObject,其方法必须是Objective-C,并且回调不能是通用的。 目标是使NSFetchedResultsControllerDelegate适应隐藏其旧的Objective-C包。 这可以通过将NSFetchedResultsController包装在一个适配器类中来完成,该适配器类确实满足旧的要求,并在纯Swift中传递新的委托回调。 第一步是将委托重新创建为Swift协议: 这里的接口几乎与NSFetchedResultsControllerDelegate完全匹配(省去了无关的controller(_:sectionIndexTitleForSectionName) )。 该关联类型被命名为ResultType,并且由于它将是NSFetchedResultsController的ResultType,因此具有NSFetchRequestResult约束,但是我们并没有通过要求编译器将Objective-C桥接到Swift泛型而混淆了编译器。 注意,我们仍然使用NSFetchedResultsController:我们还没有准备好重构它。 现在的目标是适应代表。 因此,我们保留NSFetchedResultsController及其相关的“ NSFetchedRequestResult”和“ NSFetchedResultsChangeType”。 然后可以构建适配器: 即使不对泛型进行解码,也很难避免发生的事情:来自NSFetchedResultsController的委托消息被转换并传递给FetchedResultsControllerDelegate实例。 每个细节都需要考虑,但是要逐行考虑: 类声明和属性 像大多数泛型一样,类的声明可能不是直觉的。 大致可以分为三个部分: 1) class FetchedResultsControllerAdapter FetchedResultsControllerAdapter具有单个通用类型Delegate,它是我们之前创建的FetchedResultsControllerAdapterDelegate的实例。 AdapterDelegate在类型上必须是通用的,因为正如大多数Swift开发人员所了解的那样,由于它具有Self或关联的类型要求,因此只能用作通用约束。 在整个课程中,我们将其称为“委托”。 由于Delegate具有ResultType,因此我们也可以引用它,例如在Fetched Results Controller属性中: private(set) var fetchedRequestController : NSFetchedResultsController 这是确保NSFetchedResultsController和Delegate的ResultType匹配所必需的。 2) NSObject, NSFetchedResultsControllerDelegate FetchedResultsControllerAdapter是一个NSObject,它符合NSFetchedResultsControllerDelegate的要求。 3) where Delegate: AnyObject 对于内存管理存在此约束。 代表是保留周期的经典来源。 如果此对象强烈引用其委托,使其保持活动状态,并且如果该委托强烈引用该适配器(几乎可以肯定),则使其保持活动状态,则将永远不会释放这两个对象。 […]

Swift:从Protocol到AssociatedType,然后从Type Erasure

动机 我们使用类来表示对称操作,例如“比较”,例如,如果我们想编写一个广义的排序或二进制搜索来比较两个元素,则最终结果如下: 我们对Ordered的任意实例一无所知。 因此,如果该方法不是由子类实现的,那么除了trap之外,我们无能为力。 现在,这是我们正在与类型系统进行斗争的第一个迹象。 如果我们没有意识到这一点,那也是我们开始对自己撒谎的地方。 因为我们将问题搁置一旁,告诉自己,只要Order实现的每个子类都在前面,我们就可以了。 使其成为子类的问题。 因此,我们继续实施以下示例。 它具有双精度值,我们将覆盖优先级以进行比较。 other只是任意有序,而不是数字。 因此,我们不知道other具有价值属性。 我们将Other为Number以得到正确的类型进行比较。 这是一个静态的安全孔。 类不允许我们表达self类型和他人类型之间的这种至关重要的类型关系。 这是一种代码气味。 因此,每当我们在代码中看到强制下降时,就表明一些重要的类型关系已经丢失,这通常是由于抽象类所致,这是一个好兆头。 显然,我们需要的是更好的抽象机制。 更好的抽象机制 抽象机制必须具有以下属性: 不强制接受隐式共享或丢失的类型关系 强制只选择一种抽象并在定义类型时进行 不会强制接受不需要的实例数据或相关的初始化复杂性 对于需要覆盖的内容,不会有任何歧义。 是的…!!! 协议具有所有这些属性。 不要从课堂开始。 从协议开始……! POP的时间了,不再需要OOP Swift中面向协议的编程 制作Swift时,它是第一个面向协议的。 尽管Swift非常适合面向对象的编程,但是从for循环和String 文字的工作方式到标准库对泛型的强调,从本质上讲 ,Swift都是面向协议的。 Swift中有一句话:“不要从类开始,从协议开始”。 因此,让我们使用协议重做二进制搜索示例: 哇…!!! “协议”摇滚……! 协议自我要求 一旦对协议有了自我需求,就会将协议转移到一个完全不同的世界,在该世界中,功能与类的重叠要少得多。 停止作为一种类型使用 集合变得同质而不是异质 实例之间的交互不再意味着所有模型类型之间的交互。 我们将动态多态性换成静态多态性,但是作为回报,我们为编译器提供了额外的类型信息,因此它更加可优化