Sequences | lazy

2022-07-22  本文已影响0人  精神薇

序列 Sequence

序列协议是集合类型结构中的基础。
序列代表一系列类型相同的元素,你可以对这些元素进行迭代

Sequence协议

Sequence协议是集合类型的基础,Swift中Sequence协议为序列提供了迭代的能力。Sequence 协议只要求实现makeIterator()方法,该方法返回一个迭代器Iterator;

public protocol Sequence {
  // 元素类型
  associatedtype Element 
  // 迭代器类型 == 元素类型
  associatedtype Iterator: IteratorProtocol where Iterator.Element == Element
  //迭代器
  __consuming func makeIterator() -> Iterator
  //...
}
迭代器

序列通过创建一个迭代器来提供对元素的访问。迭代器每次产生一个序列的值,并且当遍历序列时对遍历状态进行管理。在 IteratorProtocol 协议中唯一的一个方法是 next(),这个方法需要在每次被调用时返回序列中的下一个值。当序列被耗尽时,next() 返回 nil

public protocol IteratorProtocol {
  /// The type of element traversed by the iterator.
  associatedtype Element
  mutating func next() -> Element?
}

for循环的背后是编译器创建了一个迭代器,然后不断的调用next(),直到返回nil

// 猜测编译器实现 for
var iter = CustomIterator()
while let x = iter.next(){
        //...
}

例子

1.自定义迭代器类型,遵守IteratorProtocol协议,不需要指明Element类型,编译器会从next的返回类型推断出Element的类型
自定义序列,遵守Sequence协议,同样不需要指明Element类型,编译器会从makeIterator的类型中推断出Element类型。
最后通过for-in 就能不断打印结果了

struct customProtocol:IteratorProtocol{
        //Element 可以省略,编译器会从next的返回类型推断出Element的类型
        //typealias Element = Int
    func next() -> Int? {
        return 1
    }
}
//...
struct customSequence: Sequence{
        //同样,编译器会从makeIterator的类型中推断出Element类型,不需要再次指明
    func makeIterator() -> some IteratorProtocol {
        customProtocol()
    }
}
//...
var customPrint = customSequence()
for i in customPrint{
    print(i) // 由于next返回1,所以这里会无限打印 
}

2.自定义反转一个迭代器

// 先定义一个实现IteratorProtocol 的类型
struct ReverseIterator<T>:IteratorProtocol{
    typealias Element = T;
    
    var arr : [Element];
    var idx = 0;
    
    init(arr:[Element]) {
        self.arr = arr;
        idx = arr.count - 1;
    }
    
    
    mutating func next() -> T? {
        if idx < 0 {
            return nil;
        }else{
            let ele = arr[idx];
            idx = idx - 1;
            return ele;
        }
    }
}


// 再来定义sequence

struct ReverceSequence<T>:Sequence{
    
    var arr:[T];
    
    init(arr:[T]) {
        self.arr = arr;
    }
    
    __consuming func makeIterator() -> ReverseIterator<T> {
        return ReverseIterator(arr: self.arr);
    }
}



//
let array = [2,5,8,10];
for i in ReverceSequence(arr: array){
    // 10 8 5 2
   print(i, separator: "-", terminator: "-");
}

Lazy变量

惰性变量是按需初始化的存储属性,只能在struct或class中使用惰性变量。
例如,创建一个带有惰性变量的Person结构来计算BMI:

struct Person {
    var weight: Double
    var height: Double
    
    lazy var BMIIndex: Double = {
        return weight / pow(height, 2)
    }()
}
///当初始化Person对象时,BMI不会自动计算。而是在第一次引用的时候才计算
var jack = Person(weight: 90, height: 120)
print(jack.BMIIndex)

Lazy Sequences

在Swift标准库中,SequenceType和CollectionType协议都有个叫lazy的计算属性,它能返回一个特殊的LazySequence或LazyCollection。
这些类型只能被用到map、filter、flatMap这样的高阶函数中,而且是以一种惰性的方式。
对于那些不需要完全运行,可能提前退出的情况,使用lazy来进行性能优化效果会非常有效。

func increment(x: Int) -> Int {
    print("访问:\(x)")
    return x + 1
}

let array = Array(0..<10)

print("直接使用map的结果")
let incrementArr = array.map(increment)
print(incrementArr[5])

print("\n使用lazy属性的结果")
let lazyIncrementArr = array.lazy.map(increment)
print(lazyIncrementArr[5])

输出的结果:

直接使用map的结果:
访问:0
访问:1
访问:2
访问:3
访问:4
访问:5
访问:6
访问:7
访问:8
访问:9
6

使用lazy属性的结果:
访问:5
6
懒加载情景
延迟属性与闭包
// 直接方式创建
lazy var person1: Person = Person()

// 闭包方式创建
lazy var person2: Person = {
    let person = Person()
    p.name = "Tom"
    print("Tom...")
    return person
}()
let i = {
    return 0
}()

class Person {
    static let a = {
        return 1
    }()

    var b = {
        return 2
    }()
}

let leftButton: UIButton = {
    let button = UIButton(frame: buttonSize)
    button.backgroundColor = .black
    button.titleLabel?.text = "left"
    return button
}()

let rightButton: UIButton = {
    let button = UIButton(frame: buttonSize)
    button.backgroundColor = .black
    button.titleLabel?.text = "right"
    return button
}()

上一篇 下一篇

猜你喜欢

热点阅读