当前位置: 首页 > 编程日记 > 正文

你需要的大概不是 enumerated

作者:KHANLOU,原文链接,原文日期:2017-03-28
译者:四娘;校对:Cwift;定稿:CMB

Swift 标准库里最容易被滥用的就是 Sequence 的 enumerated() 函数。这个函数会返回一个新的序列,包含了初始序列里的所有元素,以及与元素相对应的编号。

enumerated() 很容易被误解。因为它给每一个元素都提供了一个编号,对于很多问题来说这是一个很简便的方案。然而,这些问题大多数都可以被另一种方式更好的解决,让我们来看一下其中的一些例子吧,要注意理解它们有什么问题,然后如何使用更好的抽象去解决它们。

使用 enumerated() 最关键的问题在于大家都认为它返回的是每一个元素和元素的索引值,但实际上并不是这样的。因为它可以适用于所有序列,而序列是不能保证有索引的,由此可知它返回的并不是索引值。下面的代码里,这个变量的名字是 offset,而不是 index,这是接下来文章里会默认使用的命名方式。offset 总是一个整型,从 0 开始,间隔为 1,跟每一个元素逐一对应。对于 Array,这刚好跟它的索引值完全一致,但除此之外的其他所有类型,都不会有这种巧合发生。让我们来看一个例子:


let array = ["a", "b", "c", "d", "e"]
let arraySlice = array[2..<5]
arraySlice[2] // => "c"
arraySlice.enumerated().first // => (0, "c")
arraySlice[0] // fatalError

我们的变量 arraySlice,毫无疑问是 ArraySlice 类型。然而,它的startIndex 很明显是 2,而不是 0,但当我们调用 enumerated()first 的时候, 它会返回一个元组,包含了一个offset,值为 0,以及它的第一个元素 “c”。

你以为,你会获得与下面等价的代码


zip(array.indices, array)

但实际上你获取到的是这个


zip((0..<array.count), array)

如果你不是在使用 Array 的话,随时可能会产生错误的行为。

而且实际上你获取到的是一个 offset,而不是 index,使用 enumerated() 也会有别的问题。很多时候你也许想用 enumerated(), 但有别的更好的抽象可以使用。让我们来看一些例子。

我见到 enumerated() 最常用的方式是对一个数组执行 enumerated,使用返回的 offset 来获取另一个数组对应的元素。


for (offset, model) in models.enumerated() {let viewController = viewControllers[offset]viewController.model = model
}

虽然这段代码可以正常运作,但前提是 modelsviewControllers 都是 Array 类型,使用整型来作为索引值类型,从 0 开始。另一个前提是这两个数组拥有相同的长度。如果models 的数组长度比 viewControllers 短的话,就会崩溃。我们还多了一个没有实际意义的多余的变量 offset。一个简洁的 Swift 实现方式应该是:


for (model, viewController) in zip(models, viewControllers) {viewController.model = model
}

这段代码更加简洁,而且适用于所有 Sequence 类型,而且可以安全地处理不等长的数组。

让我们看看另一个例子,这段代码给第一个 imageView 和它的容器以及每个 imageView 之间添加了一段 autolayout 的约束


for (offset, imageView) in imageViews.enumerated() {if offset == 0 {imageView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true} else {let imageToAnchor = imageView[offset - 1]imageView.leadingAnchor.constraint(equalTo: imageToAnchor.trailingAnchor).isActive = true}
}

这段示例代码也有同样的问题,我们想要成对的元素,但使用 enumerated() 去获取索引以便后续操作的时候,我们就需要手动去处理索引,这并没有必要。zip 在这种情况下也适用。

首先,处理容器和第一个元素的约束:


imageViews.first?.leadingAnchor.constraint(equalTo: containerView.leadingAnchor).isActive = true

接着,我们来把元素拼成一对:


for (left, right) in zip(imageViews, imageViews.dropFirst()) {left.trailingAnchor.constraint(equalTo: right.leadingAnchor).isActive = true
}

搞定,没有索引值,任何 Sequence 类型都适用,而且更加简洁。

(你也可以把这个拼对的操作封装进 extension 里,我会考虑命名为 .eachPair()

这里介绍一下 enumerated() 的使用姿势。因为你获取到的并非是索引值,而是一个整型,所以当你需要一个数字去对应到每一个元素的时候,就很适合使用 enumerated()。例如,你需要在垂直方向等距摆放多个 view,每一个 view 都需要一个 y,等于某个高度乘以 offset,enumerated() 就很适合。下面是一个例子:


for (offset, view) in views.enumerated() {view.frame.origin.y = offset * view.frame.height
}

因为这里的 offset 是作为一个数字去使用,enumerated()就可以正常运作。

使用的规则很简单:如果你是想用 enumerated() 去获取索引,那也许会有更好的方式去解决你的问题,如果你是想把它作为一个数字去使用,那就很适合?。

本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 http://swift.gg。

相关文章:

Matlab与线性代数 -- 正态分布的随机矩阵

本图文介绍了如何利用Matlab实现正态分布的随机矩阵。

修改maven本地仓库的位置及疑惑

maven的默认仓库在~/.m2/repository下&#xff0c;这个是在c盘下&#xff0c;很多系统程序都在c盘&#xff0c;而且c盘的空间有时候不够大&#xff0c;所以经常要修改本地repository的位置&#xff0c;我做的修改如下&#xff1a; 在D盘建立一个repository&#xff1a;D:\mave…

值得FS去的英雄副本

1) 奥金尼地穴腰带 18耐23智19精 22法爆28法伤2) 塞泰克大厅法杖 40耐42智 37法爆168法伤3) 暗影迷宫腰带 31耐27智 17法爆34法伤4) 奴隶围栏饰品 37法伤一定几率使施法加速320,持续6秒5) 盘牙洞穴魔杖 10智 11法爆20法伤转载于:https://www.cnblogs.com/Evanescence/archive/2…

利用C#语言实现小闹钟

本图文主要是15级团队学习成果的汇报“ 利用C#语言实现小闹钟”。

Windows和linux双系统——改动默认启动顺序

电脑上装了Windows 7和Ubantu双系统&#xff0c;因为Linux系统用的次数比較少而且还是默认的启动项对此非常不能容忍&#xff0c;因此得改动Windows为默认的启动项。 因为电脑上的系统引导程序是GRUB&#xff0c;因此改动当然也就落到Linux系统上啦。改动/boot/grub/grub.cfg该…

ThreadLocal的使用方法

ThreadLocal的含义是Thread Local Variable&#xff0c;它可以声明一个字段&#xff0c;使得不同的线程访问这个字段时&#xff0c;获取的都是不同的副本&#xff0c;互不影响。 ThreadLocal的作用和在每个Thread类声明一个字段相同&#xff0c;那么什么时候使用它呢&#xff1…

如何实现对象交互

在本篇随笔中&#xff0c;我们学习下什么是对象选择&#xff0c;投影和反投影是如何工作的&#xff0c;怎样使用Three.js构建可使用鼠标和对象交互的应用。例如当鼠标移到对象&#xff0c;对象变成红色&#xff0c;鼠标移走&#xff0c;对象又恢复原来的颜色。 本篇随笔的源代码…

Matlab与线性代数 -- 矩阵的大小

本图文介绍了如何利用Matlab求矩阵的大小。

最近做了一个小小的系统,收获挺大的....我想总结一下

首先我要感谢老许,是他给了我这次机会.以后我会把我的经验一点一点总结出来....为那些在编程之路上的迷茫者找到方向活着让人兴奋...总觉的应该去做点什么做工程开发吧----我的老师阿温说过一句话让我记忆尤新:"坚持成就传奇".我想用他去勉力每一个在人生路上奋斗的人…

Hibernate和iBATIS 优缺点比较

选择Hibernate还是iBATIS都有它的道理&#xff1a;Hibernate的特点&#xff1a;Hibernate功能强大&#xff0c;数据库无关性好&#xff0c;O/R映射能力强&#xff0c;如果你对Hibernate相当精通&#xff0c;而且对Hibernate进行了适当的封装&#xff0c;那么你的项目整个持久层…

Matlab与线性代数 -- 矩阵的秩

本图文详细介绍了利用Matlab求矩阵秩的方法。

iOS开发 最近开发了蓝牙模块,在此记录总结一下

为什么80%的码农都做不了架构师&#xff1f;>>> 1.基本概念 <1>中心者模式&#xff1a;常用的&#xff08;其实99.99%&#xff09;就是使用中心者模式作为开发&#xff0c;就是我们手机作为主机&#xff0c;连接蓝牙外设。由于开发只用到了中心者模式&#x…

asp.net实现在网页上自动显示超链接以及Email地址

人们总喜欢在帖子中加上各种有用的URL链接或Email地址。而笔者当初设计时没有考虑到这一点&#xff0c;使得这些URL链接或Email地址只能以文字的形式而并不是以超链接的形式显示&#xff0c;其它浏览帖子的人还必须把这些URL链接拷贝到浏览器中或把Email地址拷贝到Outlook中才能…

用开放地址法中的线性探查法解决冲突实现哈希表的运算

为了更深的理解哈希算法&#xff0c;自己写了用开放地址法中的线性探查法解决冲突实现哈希表的运算。 /*** Created by lirui on 14-8-13.* 用开放地址法中的线性探查法解决冲突实现哈希表的运算。*/ public class MyHashSearch {public static final int SIZE 10;public sta…

Re: 求助:5道算法题

http://www.newsmth.net/frames.html发信人: cutepig (cutepig), 信区: Algorithm标 题: 求助&#xff1a;5道算法题发信站: 水木社区 (Sat Nov 10 18:25:06 2007), 站内1)given a integer, output its previous and next neighbor number which has the same number of bit 1…

Linux下des对称性加密

最近对接公安审计一些经历 对方的需求&#xff1a; 打成zip包对zip包进行des-cbc对称性加密&#xff0c;使用约定好的 -K和-iv值比如 -K "abcd$#!" -iv "efgh$#!"加密后做base64编码起初是想尝试用 php 去做&#xff0c;经过一阵折腾之后发现&#xff0c;p…

在软件中常用的“撤销”操作,其本质是“栈”!

本文介绍了栈的定义与操作并利用顺序表和链表实现了栈这种常用的数据结构。

用拉链法实现哈希算法的运算

package lirui.find;import java.util.LinkedList;/*** Created by lirui on 14-8-13.* 用拉链法实现哈希算法的运算*/ public class MyHashSearch2 {public static final int SIZE 10;public static MyHashElement[] hashtable new MyHashElement[SIZE];// 记录hash表中的数…

C#图片处理常见方法性能比较

在.NET编程中&#xff0c;由于GDI的出现&#xff0c;使得对于图像的处理功能大大增强。在文通过一个简单黑白处理实例介绍在.NET中常见的图片处理方法和原理并比较各种方法的性能。 黑白处理原理&#xff1a;彩色图像处理成黑白效果通常有3种算法&#xff1b; (1).最大值法: 使…

软件中常用的“发送邮件”、“打印文档”,其本质是“队列”!

本图文详细介绍了顺序队列、循环队列、链队列的实现过程。

二分查找的循环实现和递归实现

自己实现了二分查找的循环实现和递归实现 说明&#xff1a;二分查找适用于顺序存储结构&#xff0c;不适于链式存储结构&#xff0c;是一个高效的查找方法。虽然折半查找效率高&#xff0c;但是要排序&#xff0c;排序本身是一种很费时的运算。要求传入的表是有序的。二分查找的…

CentOS6.8 编译安装LNMP

思路&#xff1a;根据Linux系统以及公司网站系统的信息&#xff0c;选择合适的安装包进行安装 一、查看系统信息 # uname -a # 查看内核/操作系统/CPU信息 # head -n 1 /etc/issue # 查看操作系统版本 # grep MemTotal /proc/meminfo # 查看内…

js入门·循环与判断/利用函数的简单实例/使用对象/列举对象属性的名称

1,列举对象属性的名称<script language"javascript">varobjnewObject();obj.a"您好&#xff0c;我是田洪川";obj.b"你是田洪川咋的&#xff0c;不得了啊&#xff1f;";obj.c"西西&#xff0c;哈哈&#xff0c;我是属性 c ";//上…

Matlab与数据结构 -- 对向量的排序

本图文介绍了Matlab怎样实现对向量的排序。

HashMap和HashSet原理及底层实现

HashMap底层用哈希算法实现&#xff0c;下面看一下哈希算表的整体概括&#xff1a; 当map.put(“key”,”values”);的时候&#xff0c;底层是这样的&#xff1a; static final Entry<?,?>[] EMPTY_TABLE {}; transient Entry<K,V>[] table (Entry<K,V&g…

Study on Android【三】--Intent消息传递

在前面写Android的ContentProvider时候&#xff0c;可以看到那是基于观察者模式的一个消息传递方法。每一个Cursor、ContentResolver做为一个小的注册中心&#xff0c;相关观察者可以在这个中心注册&#xff0c;更新消息由注册中心分发给各个观察者。而在MFC或Winform中&#x…

Matlab与数据结构 -- 对矩阵的排序

本图文介绍了Matlab怎样实现对矩阵的排序。

Java_中快速获取系统时间

直接调用System的currentTimeMillis()即可&#xff01; long start System.currentTimeMillis(); System.out.println("Start time : "start);

servlet必知细节(一)

servlet必知细节&#xff08;一&#xff09; 今天复习了一下servlet&#xff0c;有过一些编程经验后&#xff0c;与最初学习servlet相比&#xff0c;对servlet理解的角度不同了&#xff0c;最初只是学习了如何写一个servlet&#xff0c;api怎么用&#xff0c;现在从更深处了解了…

办公室“暧昧”的几种结局。

暧昧结局一&#xff1a;以消散结尾 外贸公司职员小雨 p: [( I J( n, i/ L( L 那是我刚来这家公司的时候&#xff0c;参加面试时我就关注到其中一个面试我的男人长得不错&#xff0c;言谈举止也都很儒雅&#xff0c;所以第一面就留下了深刻印象。等到我被录取正式上班后…