Rust学习笔记 - 函数与所有权

栏目: 编程语言 · Rust · 发布时间: 6年前

内容简介:在函数签名中,必须声明每个参数的类型。函数定义也是语句,语句不返回值。具有返回值的函数需这样定义:在 Rust 中,函数的返回值等同于函数体最后一个表达式的值。

0. 函数

在函数签名中,必须声明每个参数的类型。

fn main() {
    another_function(5, 6);
}

fn another_function(x: i32, y: i32) {
    println!("The value of x is: {}", x);
    println!("The value of y is: {}", y);
}

函数定义也是语句,语句不返回值。具有返回值的函数需这样定义:

fn main() {
    let x = plus_one(5);

    println!("The value of x is: {}", x);
}

fn plus_one(x: i32) -> i32 {
    x + 1
}

在 Rust 中,函数的返回值等同于函数体最后一个表达式的值。

1. 所有权 / owner

1.1 所有权简介

所有权有以下几个规则:

  • Rust 中的每一个值都有一个被称为其所有者的变量。
  • 值有且只有一个所有者。
  • 当所有者(变量)离开作用域,这个值将被丢弃。

以下示例展示了移动一个变量后,前一个变量无效的场景。注意,Rust 永远不会自动创建数据的“深拷贝”:

let s1 = String::from("hello");
let s2 = s1;

println!("{}, world!", s1); // error

如果我们确实需要深度复制 String 中堆上的数据,而不仅仅是栈上的数据,则需使用 clone 函数:

let s1 = String::from("hello");
let s2 = s1.clone();

println!("s1 = {}, s2 = {}", s1, s2);

如果一个类型拥有 Copy trait,一个旧的变量在将其赋值给其他变量后仍然可用。

  • 所有整数类型,比如 u32
  • 布尔类型 bool
  • 所有浮点数类型,比如 f64
  • 字符类型, char
  • 元组,当且仅当其包含的类型也都是 Copy 时。比如, (i32, i32)

一个函数间转移返回权的例子如下:

fn main() {
    let s1 = gives_ownership();         // gives_ownership 将返回值
                                        // 移给 s1

    let s2 = String::from("hello");     // s2 进入作用域

    let s3 = takes_and_gives_back(s2);  // s2 被移动到
                                        // takes_and_gives_back 中, 
                                        // 它也将返回值移给 s3
} // 这里, s3 移出作用域并被丢弃。s2 也移出作用域,但已被移走,
  // 所以什么也不会发生。s1 移出作用域并被丢弃

fn gives_ownership() -> String {             // gives_ownership 将返回值移动给
                                             // 调用它的函数
 
    let some_string = String::from("hello"); // some_string 进入作用域.

    some_string                              // 返回 some_string 并移出给调用的函数
}

// takes_and_gives_back 将传入字符串并返回该值
fn takes_and_gives_back(a_string: String) -> String { // a_string 进入作用域

    a_string  // 返回 a_string 并移出给调用的函数
}

1.2 引用与借用

引用允许我们使用值但不获取其所有权,例如:

fn main() {
    let s1 = String::from("hello");

    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize { // s 是对 String 的引用
    s.len()
}

获取引用作为函数参数被称为借用,而默认情况下不允许修改引用的值,若需修改必须创建一个可变引用。需要注意几点:

  1. 在特定作用域中的特定数据有且只能有一个可变引用,以避免数据竞争。
  2. 不能在拥有不可变引用的同时拥有可变引用。

一个可变引用的示例如下:

fn main() {
    let mut s = String::from("hello");

    change(&mut s);
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

Rust 编译器会确保引用永远不会变成悬垂状态:

fn dangle() -> &String { // dangle 返回一个字符串的引用

    let s = String::from("hello"); // s 是一个新字符串

    &s // 返回字符串 s 的引用,解决办法是直接返回 String
} // 这里 s 离开作用域并被丢弃。其内存被释放。

总结来看:

  • 在任意给定时间,要么只能有一个可变引用,要么只能有多个不可变引用。
  • 引用必须总是有效。

1.3 Slice

let s = String::from("hello world");

// .. 是 range 语法,两边下标可省略
let hello = &s[0..5]; // 不包含结束下标
let world = &s[6..=10]; // 包含结束下标

字符串字面值就是 slice。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法竞赛入门经典(第2版)

算法竞赛入门经典(第2版)

刘汝佳 / 清华大学出版社 / 2014-6-1 / CNY 49.80

《算法竞赛入门经典(第2版)》是一本算法竞赛的入门与提高教材,把C/C++语言、算法和解题有机地结合在一起,淡化理论,注重学习方法和实践技巧。全书内容分为12 章,包括程序设计入门、循环结构程序设计、数组和字符串、函数和递归、C++与STL入门、数据结构基础、暴力求解法、高效算法设计、动态规划初步、数学概念与方法、图论模型与算法、高级专题等内容,覆盖了算法竞赛入门和提高所需的主要知识点,并含有大量......一起来看看 《算法竞赛入门经典(第2版)》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具