大白话rust系列09 函数调用两次有什么错?

话不多说,直接上代码

rust 复制代码
fn main() {
    let aa: i32 = 10;
    print_i32(aa);
    print_i32(aa);
}

fn print_i32(a: i32){
    println!("aa = {a}");
}

运行结果

rust 复制代码
aa = 10
aa = 10

没有什么特别呀

那么,请看下面一段代码

rust 复制代码
fn main() {
    let city_shenzhen = String::from("ShenZhen");
    print_city(city_shenzhen);
    print_city(city_shenzhen);
}

fn print_city(city: String){
    println!("city = {city}");
}

编译报错啦:

报错信息如下:

rust 复制代码
use of moved value: `city`
value used here after move
main.rs(3, 16): value moved here
main.rs(2, 9): move occurs because `city` has type `String`, which does not implement the `Copy` trait
main.rs(7, 21): consider changing this parameter type in function `print_city` to borrow instead if owning the value isn't necessary
main.rs(3, 20): consider cloning the value if the performance cost is acceptable: `.clone()`

编译报错涉及到所有权问题,city_shenzhen作为参数传递给print_city,所有权被转移到了print_city函数内部,第一次print_city拿到参数,但是第一次调用结束后,city_shenzhen已经被销毁了,所以第二次调用会有问题。rust编译器不给你使用一个已销毁的参数

如果熟悉java和cpp等语言都知道,参数传给函数是有拷贝的动作的。这也是Rust相对于其他语言性能更好的原因,它对于一些复杂的数据,在传参时,只转移所有权,不进行拷贝

慢着,为什么文章开头那段代码,i32作为参数的函数,多次调用没有问题?

因为i32这些比较简单的数据,在拷贝的时候,性能代价一般较小,简单数据基本实现了Copy特性。

实现了Copy特性的数据,在作为参数传递时,传递的是拷贝的副本,没有所有权的转移。参数传递有两种途径,没有实现Copy特性,走所有权转移,实现了Copy特性,走拷贝副本。

如何处理String这种所有权会转移的数据需要多次调用的场景?答案是使用引用

rust 复制代码
fn main() {
    let city_shenzhen = String::from("ShenZhen");
    print_city(&city_shenzhen);
    print_city(&city_shenzhen);
}

fn print_city(mut city: &String){
    println!("city = {city}");
}

运行结果:

rust 复制代码
city = ShenZhen
city = ShenZhen

不过,有的时候希望将传递进来的String处理一下变为其他字符串,怎么做?看以下代码

rust 复制代码
fn main() {
    let mut city_shenzhen = String::from("ShenZhen");
    println!("before print_city called,city_shenzhen = {}",city_shenzhen);

    print_city(&mut city_shenzhen);
    print_city(&mut city_shenzhen);

    println!("after print_city called,city_shenzhen = {}",city_shenzhen);
}

fn print_city(city: &mut String) {
    if !city.starts_with("I am ") {
        city.insert_str(0, "I am ");
    }
    println!("{city}");
}

运行结果:

rust 复制代码
before print_city called,city_shenzhen = ShenZhen
I am ShenZhen
I am ShenZhen
after print_city called,city_shenzhen = I am ShenZhen

有时因为特殊原因只能传递String无法传递引用,但又需要多次调用,如何做呢,String没有Copy特性,但有Clone特性,这个有点类似Copy

rust 复制代码
fn main() {
    let city_shenzhen = String::from("ShenZhen");
    print_city(city_shenzhen.clone());
    print_city(city_shenzhen.clone());
}

fn print_city(mut city: String){
    println!("city = {city}");
}

运行结果:

rust 复制代码
city = ShenZhen
city = ShenZhen

这个其实就是调用String的clone函数创建了一个拷贝副本传给函数,没有所有权的转移,自然是可以多次调用的

相关推荐
学逆向的1 小时前
C 多文件开发
c语言·开发语言·网络安全
布吉岛的石头1 小时前
Java 程序员第 50 阶段3:数据工程:预训练语料清洗与去重
java·开发语言·人工智能·深度学习·transformer
benchmark_cc1 小时前
QuantDash 安装成功后,如何验证 Python 环境可以正常导入 SDK?
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
学逆向的2 小时前
C 内存属性
c语言·开发语言·算法·网络安全
康小旺2 小时前
TypeScript 编译器开始卷 Rust 了:Cloudflare 的 tsrs 到底想干嘛?
rust·typescript
Norna2 小时前
时间轮的 +1,为什么最后只留在顶层
rust
zh路西法2 小时前
【模型式强化学习】(二)PETS——从概率动力学模型到模型预测控制(MPC)
pytorch·python·强化学习·pe·mpc·ces·pets
HAPPY酷3 小时前
C++ 自定义内存池优化点云处理:从裸指针到 RAII 自动回收
开发语言·c++