窥探Swift之数组安全索引与数组切片

  在Swift中的数组和字典中下标是非常常见的,数组可以通过索引下标进行元素的查询,字典可以通过键下标来获取相应的值。在使用数组时,一个常见的致命错误就是数组越界。如果在你的应用程序中数组越界了,那么对不起,如果由着程序的性子的话是会崩溃的。为了防止崩溃呢,我们会对集合做一些安全的处理。比如对数组进行扩展,从而对数组的索引进行安全检查,保证数组的index在正常范围内。在Objective-C中也是经常对数组,字典等做一些处理操作。

  今天的博客的主要内容是先对Objective-C中常用集合的安全扩展进行介绍,由此在窥探一下Swift语言中的处理。并且还会介绍Swift中自定义下标,说白了自定义下标其实就是通过下标的形式与特定的下标值来访问一个对象。自定义下标在有些场合中是非常实用的。然后下方还会给出数组切片的概念与实用方式。废话少说进入今天的主题。

一、安全的索引集合元素

  对一个集合索引进行安全检查是很有必要的,也是经常实用的,最常见的就是对数组和字典索引的安全检查,该部分内容就是类比这Objective-C中的数组索引的安全检查来扩充Swift的数组,从而让你的Swift数组也同样具备对数组安全检查的功能。

  1. Objective-C中NSArray对索引的安全扩展

  下方这段代码是非常简单的,它是对Objective-C中的NSArray做的扩展,该方法位于NSArray相关的延展中。在你的项目中,如果添加了此段延展代码,那么你就可以通过objectAtIndexSafe:方法对数组进行安全的索引。有代码不难看出在定义该函数参数时,我们将index声明为NSUInteger,也就是正整数,这就排除了你对下标传入一个负数。紧接着又对index的合法性进行验证,如果index不在数组有效范围内,那么就返回nil。当你查找的元素不存在时,你返回nil是不会造成程序崩溃的,因为nil的地址是0x0, 这和归零若引用有些类似。

  当然下方只是NSArray安全扩展其中一个方法,还有许多扩展的安全方法,比如数组的增删改查都可以进行相应的安全扩展,扩展的方式和思路与下方这段简单代码类似,再次就不花过多的篇幅对其进行介绍了。

1 - (id)objectAtIndexSafe:(NSUInteger)index {
2     if (index > self.count-1) {
3         return nil;
4     }
5     return [self objectAtIndex:index];
6 }

  

  2.Swift中对Array的安全扩展

  上面简单的对Objective-C中的安全方法进行了简单的介绍,就算是对Swift相关内容的引子吧,下方将会给出Swift语言中类似的方法。对Swift相关方法介绍时,我会尽量的详细一些,因为毕竟本篇博客主要是关于Swift内容的。接下来将对上面Objective-C中NSArray数组索引安全验证的方法使用Swift语言进行重新。当然重写的内容也是非常容易理解的。

    (1)主要是对subscript方法进行重载,在重载的subscript方法中,对index的范围通过三目运算符进行了安全检查。如果index在0..<count这个半开区间内,那么就返回当前索引的值,如果不在该范围内就返回nil, 下方就是对Array索引的安全检查。

1 extension Array {
2     subscript (safe index: Int) -> Element? {
3         return (0..<count).contains(index) ? self[index] : nil
4     }
5 }

    

    (2)上面是对Swift中的Array进行了安全索引扩展,接下来就是简单的使用了,下方的代码段是对上面安全扩展函数的测试。首先创建了一个数组testArray, 然后创建了一个索引数组indexs, 然后遍历indexs中的元素值,将其作为testArray的下标,对testArray进行检索。当然检索时,使用的是我们上面定义的safe方法,并且在indexs下标数组中存在非法的下标。在这种情况下,我们来验证一下我们的安全方法。

    当然在数组遍历中,我们使用了for-in循环取出indexs中的每个index, 然后使用guard语句取出testArray中的值。使用guard语句能很好的过滤掉因为非法的index而返回的nil值。具体代码段如下所示:

    上面的代码段理解起来并不难,上述测试代码的运行结果如下所示,从运行结果可以很好的说明问题,并且在index非法时不会崩溃,并合理的给出相应的错误提示,请看下方具体运行结果。

    上面的延展也可以通过对整个集合类型,也就是CollectionType进行扩展,不过在扩展CollectionType时要对Index使用where子句进行限制,使Index必须符合Comparable协议,具体实现如下所示,不过下面的方法比较少用,因为一般是数组存在越界的情况,因为在字典中,如果你对一个不存在的键进行值的索引,会返回nil值,而不会崩溃。但是在数组中,你对不存在的index进行索引,就会抛出错误。下方是另一种处理方式,不过该方式用的比较少。

    实现下方延展后,同样可以在数组中使用safe方法。

  

二、使用多个索引下标的数组

  延展的功能是非常强大的,该部分将会给出另一个数组的延展。该延展的功能是可以通过多个索引给数组设置值,以及通过多个索引一次性获取多个数组的值。该功能是非常强大的,接下来将一步步实现该功能。

  1. 了解zip()函数以及Zip2Sequence

    在实现数组多个索引扩展时,需要使用到zip()函数,zip()函数接收两个序列,并且返回一个Zip2Sequence类型的数据。zip()函数究竟是干嘛的呢?接下来将会通过一个小的实例来搞一下zip()函数。首先看一下Apple的帮助文档上对zip()函数的介绍。具体如下所示:

    上面那句英文的意思大概就是“基于两个基本序列构建了一个序列对,在序列对中,第i对,代表着每个基本序列中的第i个元素。”在zip函数定义的过程中,我们可以看到,zip()是一个泛型函数,其接收两个SequenceType类型的参数,然后返回一个Zip2Sequence类型的数据。新创建的序列对就存在于Zip2Sequence中。说这么多还是来个小Demo实惠一些,通过一个小实例,看zip()函数的用法一目了然。

    (1) 创建两个数组zip1和zip2, 将这两个数组作为zip()函数的参数,将两个数组进行合并。具体实现如下:

    (2) 通过上面的程序可以看出,zipSum是一个Zip2Sequence<Array<Int>, Array<Int>>类型的常量,我们可以使用dump()对zipSum常量进行打印,观察其中的数据存储结构,具体结构如下所示:

    输出结果如下,由结果容易看出,在序列中有两个元素,第一个元素对应着数组zip1, 第二个元素对应着数组zip2。

    (3)接下来就是对zipSum这个序列通过for-in循环进行遍历,下方就是对zipSum进行遍历的代码。

      上面对zipSum遍历的结果如下所示,由下方输出结果可知,输出是成对遍历的,如果某个数组中的元素是多余的,那么就会被忽略掉。

  2. 数组多个索引的延展实现

    在这个将要实现的延展中,我们对Array进行了扩展,在延展中对subscript方法进行重载,使其可以接受多个下标,并且对多个下标对应的值进行索引,并把索引结果组成数组。在subscript方法中通过get方法获取索引相应的值,通过set方法为相应的索引值进行设置。下方代码段就是该延展的实现:    

 1 extension Array {
 2     subscript(i1: Int, i2: Int, rest: Int...) -> [Element] {
 3         //通过实现get方法,获取数组中相应的值
 4         get {
 5             var result: [Element] = [self[i1], self[i2]]
 6             for index in rest {
 7                 result.append(self[index])
 8             }
 9             return result
10         }
11
12         //通过set方法,对数组相应的索引进行设置
13         set (values) {
14             for (index, value) in zip([i1, i2] + rest, values) {
15                 self[index] = value
16             }
17         }
18     }
19 }

    在上述延展的实现中,并没有多少困难的地方。在subs两个cript函数中,使用的是可变参数,subscript函数参数的个数是两个以上(包括两个)。然后就是通过zip()函数以及对zip()函数返回的结果集进行遍历,从而对多个下标索引进行值的设置。经过上述延展,我们就可以通过多个索引对数组进行操作了。上述延展的使用方式如下: 

三、数组切片

  数组切片在OC中也是不存在的,是Swift新引入的概念,该部分将会对数组切片进行讨论,研究一下数组切片的使用方式及其特点。下方先通过一个小Demo来看一下如何生成数组切片。下方代码段先将一个字符串通过map函数转换成一个数组arrayTest, 然后我们创建一个该数组的切片。下方代码段创建了arrayTest数组中的下标3到下标6这个范围区间中的切片,arraySlices就是数组切片变量,它是ArraySlice<String>类型的,具体代码段如下所示。

  在数组切片中有一点需要注意,数组切片的下标与原始数组中的下标保持一致。如果要取出切片arraySlices中的第一个值,我们要使用arraySlices[3], 而不是arraySlices[0], 如果使用arraySlices[0]就会报错,如下所示:

  

  因为数组是值类型,尽管切片与原数组有着对应的数组下标,但是切片是原始数组的部分拷贝,所以修改切片或者修改原数组,两者互不影响,下方示例给出了该测试,如下所示:

   

  如果把切片转换成枚举,那么切片中与原始数组对应的下标关系将不存在,下方是将切片转换成枚举序列,然后对其进行遍历,代码如下:

  上述代码段输出结果如下:

    今天博客就先写到这儿,关于数组的延展还有许多,以后有机会再讨论。其实我们还可以通过一些方式来为我们自己的对象添加下标。也就是可以通过下标来访问对象属性,这个以后在讨论吧。  

时间: 2024-08-08 13:56:01

窥探Swift之数组安全索引与数组切片的相关文章

08.18 javascript 06 数组 数组的概念 创建数组 读取数组中的元素 稀疏数组 添加和删除数组的元素 数组遍历 多维数组 数组的方法 类数组对象 作为数组的字符串

# 数组 ### 数组的概念 * 数组是值的有序集合 * 数组中的每个值 称之为 元素 * 每个元素可以是任意数据类型的值 * 每个元素都有索引(下标) * 元素的索引从0开始,按照顺序递增. 元素最大的索引 2^32-2 ### 创建数组 * 直接量 `[]` * 构造函方式  `new Array()` ### 读写数组中的元素 * 数组名[索引] ### 稀疏数组 * js数组的索引是连续的 * 没有连续的给元素赋值 , 没有赋值的元素会自动赋值 undefined ### 添加和删除 数

《Inside C#》笔记(六) 属性、数组、索引器

一 属性 a) 属性可用于隐藏类的内部成员,对外提供可控的存取接口.属性相当于有些语言的getter.setter方法,只是使用起来更加方便一点,而且查看对应的IL码可以看到,属性的本质也确实是方法. b) 通过只提供get,可以让属性只读.只写属性也可以,但没有用过. c) 属性除了用来控制对类成员的访问外,还可以在get或set的时候通过编码进行一些附加的动作. d) 属性也可以被继承.重写. 二 数组 a) 在C#中,所有数组都继承自System.Array类.数组也是对象,所以声明的数组

javascript根据索引删除数组的元素

javascript根据索引删除数组的元素:根据索引值删除数组元素,就是删除指定索引的数组元素,下面就通过代码实例简单介绍一下如何实现此功能.代码如下: var theArray=["蚂蚁部落",2,"青岛市南区","antzone"]; theArray.splice(2,1); console.log(theArray); 以上代码可以删除索引值为2的元素,也就是数组中的第三个元素.splice()函数可以参阅javascript的Array

Swift的数组与OC中数组的区别

相同的值可以多次出现在一个数组的不同位置: Swift中的数组,数据值在被存储进入到某个数组之前类型必须明确,可以显示的类型标注或者类型推断.而且,Swift中的数组不必是对象类型. OC中的NSArray和NSMutableArray,他们可以存储任何类型的实例,而且不提供他们返回对象的任何本质信息. Swift的数组与OC中数组的区别,布布扣,bubuko.com

Knockout获取数组元素索引的2种方法,在MVC中实现

在遍历数组.集合的时候,通常要获取元素的索引,本篇体验使用Knockout获取索引的2种方法. 假设有这样的一个模型: namespace UseIndex.Models { public class Student { public int Id { get; set; } public string Name { get; set; } } } 在HomeController中,先模拟一个Student的集合,在投影出Name属性的集合,最后以Json返回给前台视图. using Syste

多维数组的索引越界问题

1.我们大都知道可以使用vector或array模板作为线性数组的实现,那么对于需要二维矩阵.三维数组(或者N维数组)时应该怎么解决. 由于N维数组的基本情况中的所有问题都可以用一个二维矩阵举例说明,因此以下的讨论仅限于此,并简单的称为矩阵. 如果矩阵的大小在编译时是已知的,可以很方便的把它实现为数组的数组,这个很简单.这里,我们主要把注意力集中在当矩阵的大小是在运行时计算产生,对于这种复杂的情况,我们可以很方便的使用vector或的vector来实现.事实上,如果不同的行必须必须具有不同的长度

类中属性返回形式(对象,关联数组,索引数组)

class A { public $x, $y; function __construct($x, $y)  { $this->x = $x; $this->y = $y; } function get_value($arr = true)  { if($arr == 'arr')   { // 类中属性以关联数组形式转换返回 return get_object_vars($this); }else if($arr == 'obj')   { //类中属性以对象形式返回 return $thi

(一)javascript中的数组index属性——获取数组的索引值

例如:要做到这样的效果 点击每个选项时,会显示不同的div. 我们的做法:在javascript中,先把所有的div的display设置为none,然后在根据当前的数组里的索引值进行一个显示div的过程. 下面的例子就是: 首先,把妙味课堂.妙味茶馆.苗味视频选项的div设置为display:none: 然后,早在之前就以前设置好了数组的索引值 btn[i].index=i; 于是当所有div都设置为display:none后,再把点击的那个div的display设置为block就可以了 con

如何在JS数组特定索引处指定位置插入元素?

需求: 将一个元素插入到现有数组的特定索引处.听起来很容易和常见,但需要一点时间来研究它. // 原来的数组var array = ["one", "two", "four"];// splice(position, numberOfItemsToRemove, item)// 拼接函数(索引位置, 要删除元素的数量, 元素)array.splice(2, 0, "three"); // www.jbxue.comarray;