Rust循环

for循环

for循环是一种基于迭代器的循环结构。迭代器需要实现Iterator trait.然后可以使用for循环。
不过像数组或向量这样的集合类型并不是迭代器,而是实现了IntoIterator trait,该trati定义了如何从某种类型转换为迭代器。for循环也可以直接作用于实现了IntoIterator的集合类型。

下面演示了在for循环中使用范围字面量

use std::ops::Range;

fn main() {
    let r = Range{start: 0, end: 3};
    for i in r {
        println!("{}", i);
    }

}

在迭代器中,有一个enumeratr方法,返回一个包含两个字段的元组,分别是当前项的索引和值

fn main() {
    let iter = (1..=10).enumerate();
    for value in iter {
        println!("{:?}",value);
    }
}

数组和向量不是迭代器,但是for-in会通过IntoIterator trait转换为迭代器。

fn main() {
    let vec = vec![1,2,3,4,5,6];
    for i in vec {
        println!("{}", i);
    }
}

我们尝试在数组或向量上使用enumerate方法是行不通的,因为IntoIterator trait没有提供相应的方法。
在使用enumerate之前,我们需要通过iter/iter_mut/into_iter方法将集合类型转换为迭代器。

  • iter() 生成不可变引用(&T)
  • iter_mut() 生成可变引用(&mut T)
  • into_iter() for-in默认调用的方法,通过消耗所有权将集合转化为迭代器
fn main() {
    let vec = vec![1, 2, 3, 4, 5, 6, 7];
    for value in vec.iter().enumerate() {
        println!("{:?}", value);
    }
}

尝试在遍历过程中修改不可变引用的值,会报错

fn main() {
    let mut vec = vec![1, 2, 3];

    for item in vec {
        item *= 2;
    }
    println!("{:?}",vec);
}

输出

cannot assign twice to immutable variable

这说明了,默认情况下for-in返回的是不可变的类型T,我们无法对其进行修改,因此我们需要返回一个可变引用(&mut T)。

fn main() {
    let mut vec = vec![1, 2, 3];

    for item in vec.iter_mut() {
        *item *= 2;
    }
}

而默认的T类型具有移动语义,在for-in中,这个变量的所有权也会被移走。当我们使用for-in循环时,这个变量的所有权会被移动到循环内部,这就导致for-in循环结束后,这个变量不再可用。会引起借用检查器报错。



fn main() {
    let vec = vec![1, 2, 3];

    for value in vec {
        println!("{}", value);
    }
    println!("{}", vec[0]);
}

解决方法是使用正确的迭代器。



fn main() {
    let vec = vec![1, 2, 3];

    for value in vec.iter() {
        println!("{}", value);
    }
    println!("{}", vec[0]);
}

loop表达式

loop在设计上是一个无限循环,而它不仅仅是一个"while true", 它相较于while true有额外的特性,因为loop可以用作表达式。
下面演示了找到第一个偶数的例子

fn main() {
    let vec = vec![1,5,6,4,5];
    let mut iter = vec.iter();

    let value = loop {
        let value = iter.next().unwrap();

        if value%2==0 {
            break value; 
        }

    };

    println!("{}",value)
}

循环标签

在嵌套循环中,for/while/loop通常只能break或continue当前的循环,然而在某些情况下,我们需要跳出到外层循环,或者跳过当前循环。使用循环标签可以解决这个问题。
定义标签

'label: loop
'label: while
'label: for

跳出标签

break 'label;
continue 'label;

示例

fn main() {
    'label: for i in 1..=10 {
        for j in 1..=10 {
            print!("{}", j);
            if j == 5 {
                println!();
                continue 'label;
            }
        }
    }
}

Iterator trait

迭代器可以从头到尾遍历一个元素序列,可以很方便地和for/while/loop结合使用。

  • 迭代器包含正向迭代器和反向迭代器。你也可以让迭代器返回普通的/可变引用/不可变引用的项
  • 迭代器实现了Iterator trait。通常实现迭代器的类型都会维护一个游标,被称为项(Item),也就是关联类型。
  • 对于实现了Iterator trait的类型,next是唯一必须实现的方法。
  • next方法会按顺序依次返回每个项,返回结果要么是Some<T>要么在项目遍历完后返回None。
  • 迭代器的next方法会在for-in循环中被隐式调用,而使用while或loop时需要显式调用。
struct Triangular(i32);

impl Iterator for Triangular {
    type Item = i32;

    fn next(&mut self) -> Option<i32> {
        self.0 += 1;
        Some(self.0 * (self.0 + 1) / 2)
    }

}

fn main() {
    for t in Triangular(0).take(6) {
        println!("{}", t);
    }

}

需要注意的是,这个三角序列是无穷的,next函数永远不会返回None,因此for-in会无限循环,相应的,使用take方法来仅返回前6项。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值