这儿每天同享一个 iOS 的新知识,快来重视我吧
前言
swift 中有一些比较奇怪的规划,其间切片的索引问题就经常被诟病,今天来具体讲讲。
首要来猜测以下代码输出什么内容:
vararr=[1,2,3,4]
varsubArr=arr[1..<3]
print(subArr[0])
切片索引并非都从 0 开端
发布成果,以上代码会产生越界溃散。
有些人看到这个成果会比较奇怪,subArr = arr[1..<3]
的成果分明是 [2, 3],那 subArr[0]
应该是 2 啊,为什么会越界呢?
其实经过 arr[1..<3]
这种办法获得的是一个 ArraySlice<Element>
类型,也叫数组切片。
看下这个函数的声明:
publicsubscript(bounds:Range<Int>)->ArraySlice<Element>
依照苹果官方文档的说法,这个 ArraySlice
和原数组同享内存,一起也同享索引,这样做的意图一方面是能够节省内存,另一方面能够进步大数组的操作功率。
因而我们上边的比如中 subArr
有用的索引应该为 1、2(同享父数组索引)。这点能够经过打印索引看出来:
vararr=[1,2,3,4]
varsubArr=arr[1..<3]
//打印索引
print(subArr.indices)//打印1..<3
得出这个结论后,我们再测验获取 subArr 的第一个元素,应该直接取下标 1:
vararr=[1,2,3,4]
varsubArr=arr[1..<3]
print(subArr[1])//打印:2
怎么处理这个隐患
这种规划难以用正常思想理解,我查看了一些论坛中的讨论,关于这个规划也不太容易修改掉,由于在调集及其子序列之间同享索引是 Swift 调集算法规划的重要组成部分(说白了就是积重难返了)。
要避免这个坑也有一些办法,比如,我们能够在 ArraySlice
的扩展中写一个新的下标办法来做一层维护(避免溃散):
extensionArraySlice{
subscript(`safe`index:Index)->Element?{
ifindices.contains(index){
returnself[index]
}else{
returnnil
}
}
}
此类办法在之前的文章避免数组越界中也说到过。
其实苹果官方有说到,要安全地引用切片的开端和结束索引,始终运用 startIndex
和 endIndex
特点而不是特定值,也就是说,索引的开端位置纷歧定为 0,而是 startIndex
,因而也能够在扩展中增加另一个办法,兼容这种状况:
extensionArraySlice{
subscript(safeOffsetoffset:Int)->Element?{
letindex=startIndex+offset
returnindices.contains(index)?self[index]:nil
}
}
这样的话,外界就能够默许切片的索引是从 0 开端的了,运用的时候:
vararr=[1,2,3,4]
varsubArr=arr[1..<3]
ifletfirst=subArr[safeOffset:0]{
print(first)//打印:2
}
这儿每天同享一个 iOS 的新知识,快来重视我吧
本文同步自微信公众号 “iOS新知”,每天准时同享一个新知识,这儿只是同步,想要及时学到就来重视我吧!