Collection 安全取值

需求:

对于数组或者 Data 等类型需要做一个类似切割的操作, 比如 123456, 想要在没两个字符后面添加 “:”, 结果是 12:34:56

方案有很多办法, 肯定是依赖 while 或者 for

现在通过系统的两个方法实现安全取值, 此方式比 sub 截取子段安全

一个是 prefix, 另一个是 dropFirst

prefix: 效果是获取从开始位置起固定长度的子段

dropFirst: 效果是获取从固定长度起到结束位置的子段


var data: String = "123456"

var result: String = ""

let interval: Int = 2

while data.isEmpty == false {

 let prefix = data.prefix(interval)

 let drop = data.dropFirst(interval)

 result.append(contentsOf: prefix)

 if drop.isEmpty == false {

 result.append(contentsOf: ":")

 }

 data = String(drop)

}

print("data: \(data), result: \(result)")

通过 Collection 源码 可以知道 prefix 和 dropFirst 都是调用


func index(

 _ i: Index, offsetBy distance: Int, limitedBy limit: Index

 ) -> Index?

prefix 和 dropFirst 源码:


@inlinable

 public __consuming func prefix(_ maxLength: Int) -> SubSequence {

 _precondition(

 maxLength >= 0,

 "Can't take a prefix of negative length from a collection")

 let end = index(startIndex,

 offsetBy: maxLength, limitedBy: endIndex) ?? endIndex

 return self[startIndex..<end]

 }

@inlinable

 public __consuming func dropFirst(_ k: Int = 1) -> SubSequence {

 _precondition(k >= 0, "Can't drop a negative number of elements from a collection")

 let start = index(startIndex, offsetBy: k, limitedBy: endIndex) ?? endIndex

 return self[start..<endIndex]

 }

offsetBy:limitedBy: 方法源码中实际调用了 for 循环, 所以单独调用 prefix 和 dropFirst 就是两次 for, 为了满足需求并减少 for 可以自己模仿源码实现, 如图

最后把这一步可以抽成一个扩展:


extension Collection {

 func split(maxLength: Int) -> (prefix: SubSequence, drop: SubSequence) {

 let index = index(startIndex, offsetBy: maxLength, limitedBy: endIndex) ?? endIndex

 return (self[startIndex..<index], self[index..<endIndex])

 }

}

该方式的优点就是很安全不会crash

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容