【Rust自学】4.3. 所有权与函数

4.3.0 写在正文之前

在学习了Rust的通用编程概念后,就来到了整个Rust的重中之重------所有权,它跟其他语言都不太一样,很多初学者觉得学起来很难。这个章节就旨在让初学者能够完全掌握这个特性。

本章有三小节:

  • 所有权:栈内存 vs. 堆内存
  • 所有权规则、内存与分配
  • 所有权与函数(本文)

喜欢的话记得点赞、收藏加关注哦,想要跟着学下去记得关注专栏哦

4.3.1. 把值传递给函数

在语义上,把值传递给函数和把值赋给变量是类似的 ,所以一句话总结:函数参数传递跟赋值操作是一样的

接下来详细解释一下:把值传递给函数将会发生移动 (Move)或者复制(Copy)

  • 对于实现了Copy trait的数据类型,会发生复制,所以原本的变量不受影响,能够继续使用
  • 对于没有实现Copy trait的数据类型,会发生复制,所以原本的变量会被弃用,不可使用

Copy trait、移动、复制的详细介绍在上一篇文章4.2. 所有权规则、内存与分配有讲,这里不再作阐述

rust 复制代码
fn main(){
	let machine = String::from("6657");
	wjq(machine);

	let x = 6657;
	wjq_copy(x);
	println!("x is:{}", x);
}

fn wjq(some_string::String){
	println!("{}", some_string);
}

fn wjq_copy(some_number::i32){
	println!("{}", some_number);
}
  • 对于变量machine

    • String 是一种复杂数据类型,分配在堆上,并且没有实现Copy trait。
    • machine 被传递给 wjq 函数时,发生了移动 (Move),即所有权从变量 machine 转移到了函数参数 some_string
    • 此时,machine 的所有权被转移,函数 wjq 可以正常使用它,但原来的变量 machine 不再可用。如果尝试在之后使用 machine,编译器会报错。
  • 对于变量x

    • i32 是一种基本数据类型,大小固定,分配在栈上,并且实现了 Copy trait。
    • x 被传递给 wjq_copy 函数时,发生了复制 (Copy),即变量 x 的值被复制了一份传递给了函数参数 some_number
    • 由于是值的复制,原变量 x 不受影响,可以在函数调用之后继续使用。
  • 对于变量some_string

    • 其作用域从第10行被声明开始,到第12行的}时就离开了作用域
    • 在离开作用域时Rust会自动调用drop函数释放变量some_string所占的内存
  • 对于变量some_number

    • 其作用域是从第14行被声明开始,到第16行的}时就离开了作用域
    • 离开作用域时不会有特殊的事情发生,因为实现了Copy trait的类型在离开作用域时不会调用 Drop

4.3.2. 返回值与作用域

函数在返回值的过程中同样也会发生所有权的转移。

rust 复制代码
fn main(){
	let s1 = give_ownership();
	let s2 = String::from("6657");
	let s3 = takes_and_gives_back(s2);
}

fn give_ownership() -> String {
	let some_string = String::from("machine");
	some_string
}

fn takes_and_gives_back(a_string:String) -> String {
	a_string
}
  • 函数 give_ownership 的行为:

    • give_ownership 函数创建了一个 String 类型的变量 some_string,它的所有权属于 give_ownership 函数。
    • some_string 作为返回值返回时,其所有权被转移到调用者,即变量 s1
    • 结果是,some_string 离开 give_ownership 的作用域后不会被释放,因为它的所有权已交给 s1
  • 函数 takes_and_gives_back 的行为:

    • takes_and_gives_back 函数接受一个 String 类型的参数 a_string。调用该函数时,传入的参数(s2)的所有权被转移到函数的参数 a_string
    • 函数将 a_string 返回时,其所有权从 a_string 再次转移给调用者,即变量 s3
    • 此时,变量 s2 不再可用,因为其所有权已被转移给 takes_and_gives_back,而函数的返回值赋给了 s3

一个变量的所有权总是遵循同样的模式:

  • 把一个值赋给其它变量时就会发生移动 ,只有实现了Copy trait 的类型(如基本类型i32, f64 等),在赋值时才会进行复制
  • 当一个包含堆数据的变量离开作用域时,它的值就会被drop函数清理掉,除非数据的所有权被移动到另一个变量上。

4.3.3. 让函数使用某个值而不获得其所有权

有的时候代码的本意是让函数使用变量,但不想因此失去对数据的使用权,这时候就可以这么写:

rust 复制代码
fn main(){
	let s1 = String::from("Hello");
	let (s2, len) = calculate_length(s1);
	println!("The length of '{}' is {}", s2, len);
}

fn calculate_length(s:String) -> (String, uszie) {
	let length = s.len();
	(s, length)
}

在这个例子中,s1不得不把所有权交给s,但这个函数在返回时把s也原封不动地返回,把数据所有权交给了s2,这样做就把数据所有权又交给了main函数里的变量,使得s1下的数据又能够在main函数中使用(虽然换了个变量名)。

这种做法太麻烦,也太笨了。 Rust针对这种场景有一个特性叫引用(Reference),让函数使用某个值而不获得其所有权。 这个特性将会在下篇文章中讲。

相关推荐
红尘散仙3 小时前
我把终端小说阅读器接上了 AI Agent:TRNovel 现在能用 skill 生成书源了
人工智能·后端·rust
卷毛的技术笔记5 小时前
告别硬编码!Spring AI Alibaba 实现 AI Agent 智能工具调用(Tool Calling)
java·人工智能·后端·python·spring·ai编程
isyangli_blog5 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008115 小时前
FastAPI APIRouter
开发语言·python
Benszen5 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆5 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木5 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
喵个咪5 小时前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
杨充5 小时前
1.3 浮点型数据设计灵魂
开发语言·python·算法
噜噜噜阿鲁~6 小时前
python学习笔记 | 11.3、面向对象高级编程-多重继承
java·开发语言