V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dxatgp02
V2EX  ›  Rust

萌新 rust 一个关于作用域的问题

  •  
  •   dxatgp02 · 311 天前 · 1566 次点击
    这是一个创建于 311 天前的主题,其中的信息可能已经有所发展或是发生改变。
    fn main(){
    
    	let s2 = test();
        
        println!("s2={}",s2 );
    }
    
    fn test() -> String{
    	let s1 = String::from("test1");
        return s1
    }
    

    打印出 s2=test1

    这里有一个疑问,s1 对应的内存有没有被销毁? return s1 这时作用域已完成,不是因销毁 s1 吗,那返回到 main 里的是什么? “test1"这 string 是否于内存中复制过?

    11 条回复    2024-03-29 18:43:33 +08:00
    sunjiayao
        1
    sunjiayao  
       311 天前   ❤️ 1
    s1 的所有权给 s2 了
    sleeepyy
        2
    sleeepyy  
       311 天前   ❤️ 1
    没有销毁,return 的时候把所有权给 s2 了
    yelog
        3
    yelog  
       311 天前   ❤️ 1
    上面两位老哥说的很好, 我补充一下官网原文关于这块的描述和示例, 可以尝试理解一下

    https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html#return-values-and-scope
    ch3nOr
        4
    ch3nOr  
       311 天前   ❤️ 1
    修改了一下楼主的程序,打印了一下内存地址,发现在 test 内 move 内存地址也会发生改变,move 到外部也会

    https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=fcfb04f8f33db75f1934513021102b30
    dxatgp02
        5
    dxatgp02  
    OP
       311 天前
    感谢各位大佬的指点自己的理解力有限,感觉被绕进去了。
    detached
        6
    detached  
       311 天前   ❤️ 2
    @ch3nOr 这个是符合预期的,"test1"这个字符串所在的内存并没有发生变化。而每一个 variable(s1,s2,s3)都是一个新的,他们均指向这个字符串。
    ch3nOr
        7
    ch3nOr  
       311 天前   ❤️ 2
    @detached

    验证了一下,确实是这样的:

    https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8e72d327ee3e3379797b5b156f034ad3


    上面 #4 的程序打印的是 s1 、s2 、s3 的地址
    docxs
        8
    docxs  
       311 天前 via iPhone   ❤️ 1
    你对比理解成 cpp 的 move ,就好理解了
    araraloren
        9
    araraloren  
       309 天前   ❤️ 1
    It transfer the ownership of s1 to s2(move is bitwise copy, but not call the drop of `s1`).
    And `s2` will be dropped when out of scope of main.
    buxudashi
        10
    buxudashi  
       305 天前   ❤️ 1
    你认为的消毁是什么?

    把全部内存段内的位变成 0 ?

    事实上的销毁是。你不管里面的数据是什么。你不取值不引用它的索引就算销了。
    Terry166
        11
    Terry166  
       237 天前
    String 是一个可变的,堆上分配的 UTF-8 的字节缓冲区,它是可增长的、可变的、有所有权的、UTF-8 编码的字符串类型,使用 to_string 或者 String::from 创建。

    fn test() -> String{
    let s1 = String::from("test1");
    return s1
    } // 创建并返回一个具有所有权的字符串,

    let s2 = test(); // 把所有权转移给 s2 ,s1 就失效了。

    内存表示如下:
    [–––––– s1 –––––] [–––––s2 –––] // 栈上的胖指针(包含三个字:地址,容量,大小)
    +–––+–––+–––+–––+–––+–––+–––
    stack frame │ │ │ │ • │ 8 │ 5 │
    +–––+–––+–––+– │–+–––+–––+–│
    │ │
    +––––––––––––––+

    +–V–+–––+–––+–––+–––+–––+–––+–––+–
    heap │ t │ e │ s │ t │ 1 │ l │ │ │ // 保存在堆上的数据
    +–––+–––+–––+–––+–––+–––+–––+–––+–
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3492 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 11:16 · PVG 19:16 · LAX 03:16 · JFK 06:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.