理解Rust的引用与借用

困惑

接触Rust也一段时间了,但对References(引用) 、borrowing(借用) 、 &关键字、ref关键字、* 关键字,这几个词非常困惑。常见的问题不在乎下面几条:

  1. &关键字是代表引用还是借用?
  2. ref 和 & 有什么区别?
  3. 总是与c++的引用对比,他们意思相同?(因为人在学习中总与现有的知识对比,所以有了这一条)

网上有很多对Rust中引用和借用部分进行翻译和解释。看得真是云里雾里,一会说借用,一会说引用,那到底是引用还是借用?

现象

rust中借用和引用的附带功效都一样,就是都有生命周期。借用使用&关键字,引用使用ref关键字。借用的对象是必须存在的,引用的对象可以虚拟的,后期附上对象。

我看这网上的一段解释,Rust的引用和c++ 语言的引用完全不一样啊,c++ 语言说的是,引用类似变量别名,声明引用时,必须同时对其进行初始化。

引用的声明方法:类型标识符 &引用名=目标变量名

再看下出自《Programming Rust Fast, Safe Systems Development》

in Rust terminology, we say that it borrows a reference to x. Given a
reference r, the expression *r refers to the value r points to. These are very much like
the & and * operators in C and C++
Unlike C pointers, however, Rust references are never null: there is simply no way to
produce a null reference in safe Rust. And Rust references are immutable by default:

这怎么拿Rust引用与C++的指针进行比较了。都不知道那种是更合理的解释。

实践

实践出真知,还是动动手。

  • 首先证明的是引用是否可以为空。
let ref a:i32;
//a = 1;  // expected &i32,consider borrowing here: `&1`
a = &1;

上面代码能编译通过,这说明Rust中的引用和c++ 中的引用不是一个意思,更像c++ 中的指针类型。c++ 通过int *a来声明指针类型。

  • ref 与 & 的区别
let ref a=2;
let a = &2;

两个值都是&i32类型。

所以ref用在变量绑定与&用在表达式上是一样的效果。
看到上一个例子的错误提示,consider borrowing here,那么&在Rust的表达式上可以看成是借用,这与c++ 取地址符是一个意思。

struct B<'l> {
    pub a: &'l u32,
    // pub b: ref u32, expected type, found keyword `ref`
}

let ref a = &1;
let b = B{ a: a };

在类型声明上,&表示引用类型。

  • & 与 * 的关系

那么&用在绑定上是怎么样的?其实&用在绑定上与*用在表达式上是一样的:

let r=&1;
let &a=r;
let a=*r;

两个值都是i32类型。

如果上面的解释还没有让你明白他们之间的关系,那么通过代码直接输出具体类型,这能加深理解。

#![feature(core_intrinsics)]

fn main() {
    let x = &false;
    print_type_name_of(x);

    let &x = &false;
    print_type_name_of(x);

    let ref x = &false;
    print_type_name_of(x);
}

fn print_type_name_of<T>(_: T) {
    println!("{}", unsafe { std::intrinsics::type_name::<T>() })
}
&bool
bool
&&bool

例子:

#![feature(core_intrinsics)]
enum Favour<'a> {
    Nor(u32),
    NorRef(u32),
    Ref(&'a u32),
    RefRef(&'a u32),
}

fn config(data: &u32) {
    println!("log data: {}", data);
}

// fn con(data: ref u32){  //expected type, found keyword `ref`
//     println!("log data: {}", data);
// }

fn log(fav: Favour) {
    match fav {
        Favour::Nor(data) => {
            config(&data);
            print_type_name_of(data);
        },
        Favour::NorRef(ref data) => {
            config(data);
            print_type_name_of(data);
        },
        Favour::Ref(data) => {
            config(data);
            print_type_name_of(data);
        },
        Favour::RefRef(ref data) => {
            config(data);
            print_type_name_of(data);
        }
    }
}

fn print_type_name_of<T>(_: T) {
    println!("{}", unsafe { std::intrinsics::type_name::<T>() })
}

fn main() {
    log(Favour::Nor(1));
    log(Favour::Ref(&2));
    log(Favour::NorRef(3));
    log(Favour::RefRef(&4));
}


log data: 1
u32
log data: 2
&u32
log data: 3
&u32
log data: 4
&&u32

match的模式匹配上只能使用 ref,在函数声明上只能使用&来表示引用类型

总结

单纯Rust语言上考虑。
我们在不同情况下解释&的意思:

  1. 在表达式上,表示的是借用。
  2. 在变量绑定上,表示解地址操作与*类似。
  3. 在类型声明上,表示引用类型。
  4. 在模式匹配上,无效关键字

那么ref的通用解释是:

  1. 在表达式上,无效关键字
  2. 在变量绑定上,表示引用类型。
  3. 在类型声明上,无效关键字
  4. 在模式匹配上,表示引用类型。

非要给区分ref&到底哪个是引用,哪个是借用。我们可以先从词性划分,引用我归类为名词,而借用归类为动词。&A在表达式上 表示借用A,这是一个动作,那结果就是产出一个引用类型。所以let ref B表示声明了一个引用类型,它只能绑定到某次借用动作上。

所以ref 更适合叫引用, &叫借用。

参考:

when-to-ref-or
ref-keyword-versus
rust-by-example

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容