Rust基础语法1

news2024/9/23 7:22:44

    所有权转移,Rust中没有垃圾收集器,使用所有权规则确保内存安全,所有权规则如下:

    1、每个值在Rust中都有一个被称为其所有者(owner)的变量,值在任何时候只能有一个所有者。

    2、当所有者离开作用域,这个值将被丢弃。

    3、所有权的转移时零成本的,这里不需要对新的变量开辟一块内存用于存储数据。新变量只是重新分配了资源的所有权。

    例子1:所有权传递(变量)

    fn main()
    {
        let x="hello".to_string();//"hello"的所有者为x
        let y=x;//"hello"的所有者变为y,这个时候原来的所有者x已失效
        println!("{}",x);//
    }

例子2:所有权传递(函数)

    fn create_string() ->String 
    {
        // 创建并返回一个新的String
        String::from("Hell,ownership!")
    }

    fn transfer_ownership(s:String) -> String 
    {
        //返回输入的String,转移所有权
        s
    }

    fn main() {
        //create_string函数创建了一个值"Hell,ownership!",并将所有权传递给了my_string。
        let my_string=create_string(); 
        //my_string将值"Hell,ownership!"的所有权传递给了函数transfer_ownership,函数又将所有权传递给了transferred_string
        let transferred_string=transfer_ownership(my_string);
        //此时my_string已不再对值"Hell,ownership!"拥有所有权。
        println!("my_string string: {}", my_string); 
        // 此时transferred_string对值"Hell,ownership!"拥有所有权。
        println!("Transferred string: {}", transferred_string); 
    }

    克隆:

    1、当克隆一个变量时,相当于创建了数据的一个完整副本。

    2、与所有权转移相比,克隆的成本较大,因为涉及到了要内存的使用和数据的复制。

    3、所有权转移后原始变量失效,克隆之后原始变量仍然有效,并且原始变量保留了数据的所有权。这里需要注意,克隆后,两个变量是完全独立的数据实例。

    例子3:

    fn main()
    {
        let x="Hello".to_string();//x获取了"Hello"的所有权
        let y=x.clone();//传递x的副本给y
        clone_ownership(y);//传递x的副本y给函数clone_ownership
        //x依然对"Hello"拥有所有权
        println!("x String:{}",x);
        //y对"Hello"还拥有所有权吗?不再拥有所有权了,因为已经将所有权传递给了函数clone_ownership
        // println!("y String:{}",y);
    }

    fn clone_ownership(s:String)
    {
        println!("{}",s);
    }

    引用:

    1、引用有可变引用(&mut T)和不可变引用(&T)。

    2、可变引用允许修改引用所指向的值,而不可变引用不允许修改引用所指向的值。

    3、为了防止数据竞争,Rust中在任何时间,只能拥有一个可变引用到特定的数据。

    4、由于不可变引用不会改变数据,Rust中可以拥有任意数量的不可变引用。

     例子4:

// 定义一个函数,它接受一个整数的不可变引用
fn print_int(value:&i32)
{
    // 打印出传入整数的值
    println!("The value is: {}",value);
}

fn  main()
{
    let _int=11;
    // 调用函数,传入整数的不可变引用
    print_int(&_int); 
}

    例子5:

// 定义一个函数,它接受一个整数的可变引用
fn print_int(value:&mut i32)
{
    // 将整数的值加倍
    *value *=10; 
}

fn  main()
{
    let mut _int=10;
    // 调用函数,传入整数的可变引用
    print_int(&mut _int);
    // 打印加倍后的整数值
    println!("The value is :{}",_int);   
}

5、生命周期参数,它可以告诉编辑器,参数的引用和返回值的引用都具有相同的生命周期。例子6中的'a就是生命周期参数

 

    例子6
    fn return_reference<'a>(data:&'a String)->&'a String
    {
        data //返回的引用与输入的引用具有相同的生命周期
    }

    fn main()
    {
        let external_string=String::from("Hello world");
        let string_ref=return_reference(&external_string);
        println!("{}",string_ref);// 这是安全的,因为external_string的生命周期贯穿了整个main函数
    }
    例子7
    //定义一个包含引用的结构体,需要生命周期注解
    struct  Item<'a>
    {
        //'a表示引用的生命周期
        name:&'a str,
    }

    // 实现结构体,战术如何使用生命周期
    impl<'a> Item<'a>
    {
        // 创建一个新的Item实例,返回一个带有生命周期的实例
        fn new(name:&'a str)->Self{
            Item {name}
        }
    }

    fn main()
    {
        let name =String::from("Rust Programming");// 创建一个String类型的变量
        let item= Item::new(&name);//借用name的引用来创建Item实例

        println!("Item name:{}",item.name);//打印Item中的name字段
    }//name的生命周期结束,item.name的引用也不再有效
    例子8
    fn print_shorter(r:&str)
    {
        println!("The string is:{}",r);
    }

    fn main(){
        let long_lived_string=String::from("This is a long-lived string.");
        {
            let short_lived_str:&str=&long_lived_string;//创建一个常生命周期的引用
            // 下面的函数调用中,short_lived_str的生命周期会被强制缩短以匹配print_shorter
            print_shorter(short_lived_str);
        }//short_lived_str的生命周期结束
        //这里long_lived_string仍然有效,因此上面的强制转换是安全的
        println!("{}",long_lived_string);
    }
    例子9
    fn main()
    {
        let mut data=vec![1,2,3,4,5];
        //创建一个不可变引用
        let data_ref=&data;
        //打印使用不可变引用的数据
        println!("Values via immutable reference:{:?}",data_ref);

        // 下面尝试创建一个可变引用将会失败,因为`data`已经被不可变引用借用
        let data_mut_ref = &mut data; 
        println!("{}", data_mut_ref);// 这行会导致编译错误,编译错误如下图

        //下面尝试创建一个可变引用将不会失败
        // let data_mut_ref=&mut data;
        // println!("{:?}",data_mut_ref);

        //只有当不可变引用不再使用后,才能创建可变引用
        //这里不再使用不可变引用data_ref,因此可以创建可变引用

        // let data_mut_ref=&mut data;
        // data_mut_ref.push(6);
        // println!("Values after mutation:{:?}",data_mut_ref);

    }

从错误截图上看,只有使用{:?}编译器错误就不存在了。

    例子10:如果有一个或多个不可变引用&T,那么在同一作用域内不能有可变引用&mut T。
如果有一个可变引用&mut T,那么在同一作用域内不能有其他的可变引用或不可变引用&T。
编译器报错提示如下
    struct MyStruct{
        value:i32,
    }

    //这个函数尝试同时接受一个对象的可变和不可变引用
    fn example_fn(mutable_ref:&mut MyStruct,immutable_ref:&MyStruct){
        println!("Mutable reference value:{}",mutable_ref.value);
        println!("Immutable reference value:{}",immutable_ref);
    }

    fn  main() {
        let mut my_object=MyStruct{value:10};
        //尝试同时借用可变引用和不可变引用
        example_fn(&mut my_object, &my_object);
    }

 

 

    例子11:
    fn main()
    {
        let x=10;//定义一个整数变量x
        let y=&x;//创建一个指向x的引用y

        println!("The value of x is:{}",x);//直接打印变量x的值。
        println!("The address of x is:{:p}",y);//打印引用y的地址,使用{:p}格式化指针地址
        println!("The value of y is:{}",y);//打印应用y的值,这里会打印出地址  注意这里打印出来的是10而不是地址,不确定是不是Rust版本的问题。
        println!("The value pointed to by is :{}",*y);//使用解引用操作符来打印y指向的值
    }
    例子12
    // 定义一个包含字符串引用的结构体Book
    struct Book<'a>{
        //'a是一个生命周期注解,表示title的生命周期
        title:&'a str,
    }

    fn main(){
        let title=String::from("The Rust Programming Language");
        let book=Book{
            //title 是一个字符串切片,他引用了title变量的数据
            title:&title,
        };
        println!("Book title:{}",book.title);
    }
    例子13
    // longset 函数定义了一个生命周期参数'a,这个生命周期参数制定了输入参数和返回值的生命周期必须相同。
    fn longset<'a>(x:&'a str,y:&'a str)->&'a str
    {
        if x.len()>y.len(){
            x// 如果x的长度大于y,返回x
        }
        else {
            y //否则,返回y
        }
    }

    fn main()
    {
        let string1=String::from("Rust");
        let string2=String::from("C++");
        let result=longset(string1.as_str(), string2.as_str());//longset函数比较两个字符串切片的长度
        println!("The longeset string is {}",result);
        //注意 result 的生命周期与string1和string2的生命周期相关,因此它们必须在result被使用之前保持有效
    }
    例子14
    // 定义一个结构体ImportantExcerpt,它包含一个字符串切片字段part
    struct  ImportantExcerpt<'a>
    {
        part:&'a str,
    }

    fn main()
    {
        let novel=String::from("Call me ishmael. Some years ago ...");
        let first_sentence=novel.split('.').next().expect("Could not find a '.'");
        let excerpt=ImportantExcerpt{
            part:first_sentence,
        };

        //打印出结构体中的字符串切片
        println!("Important excerpt:{}",excerpt.part);
    }
    例子15
    // 定义一个结构体ImportantExcerpt,它包含一个字符串切片字段part
    struct  ImportantExcerpt<'a>    
    {
        part:&'a str,
    }

    //为ImportantExcept结构体实现方法
    impl <'a> ImportantExcerpt<'a> {
        fn announce_and_return_part(&self,announcement:&str)->&str{
            println!("Attention please:{}",announcement);
            self.part
        }
    }

    fn main()
    {
        let novel=String::from("Call me ishmael. Some years ago ...");
        let first_sentence=novel.split('.').next().expect("Could not find a '.'");
        let excerpt=ImportantExcerpt{
            part:first_sentence,
        };

        let announcement="I'm going to tell you something important!";
        let part=excerpt.announce_and_return_part(announcement);
        //打印出结构体中的字符串切片
        println!("Important excerpt:{}",part);  
    }
    例子16
    //定义一个拥有静态生命周期的字符串常量
    static MESSAGE:&'static str="Hello,this is a static lifetime example";

    fn main()
    {
        //打印这个静态生命周期的字符串
        println!("{}",MESSAGE);
    }
    例子17
    //定义一个函数,该函数接收两个引用参数:一个是不带生命周期的引用,另一个是带生命周期的'a的引用
    fn select<'a>(first:&i32,second:&'a i32)->&'a i32{
        //这里我们简单地返回第二个参数,它带有生命周期'a
        second
    }

    fn main()
    {
        let num1=10;
        let num2=20;

        //创建一个生命周期较长的引用
        let result;
        {
            let num3=num2;
            //调用函数,num1的引用不带生命周期,num3的引用带有生命周期
            result=select(&num1, &num3);
        }//num3的生命周期结束

        //打印结果,result引用的是num2,因为它与num3共享相同的数据
        println!("The selected number is {}",result);
    }
    例子18
    //定义一个结构体Book,包含一个字符串切片引用,代码书名
    struct Book<'a>{
        name:&'a str,
    }

    //实现Book结构体的一个方法get_name,返回书名的引用
    //这里没有显示标注生命周期,因为编译器会自动应用生命周期省略规则
    impl<'a> Book<'a>
    {
        //根据省略规则,这里的返回值生命周期被自动推导问为与&self相同
        fn get_name(&self)->&str{
            self.name
        }    
    }

    fn main()
    {
        let book=Book{name:"The Rust Programming Language"};

        //调用get_name方法,打印返回的书名引用
        println!("Book name:{}",book.get_name());
    }
例子19
// 定义一个泛型函数`slice_first`,它有一个泛型类型`T`和生命周期`'a`
fn slice_first<'a, T>(data: &'a [T]) -> Option<&'a T> {
    // 使用`.get()`方法来尝试获取slice的第一个元素的引用
    // 如果存在,则返回Some(&T),否则返回None
    data.get(0)
}

fn main() {
    // 创建一个整数类型的slice
    let numbers = vec![1, 2, 3, 4, 5];
    // 调用`slice_first`函数,并打印返回的结果
    if let Some(first) = slice_first(&numbers) {
        println!("The first number is {}", first);
    } else {
        println!("The slice is empty.");
    }

    // 创建一个字符类型的slice
    let letters = vec!['a', 'b', 'c', 'd', 'e'];
    // 同样调用`slice_first`函数,并打印返回的结果
    if let Some(first) = slice_first(&letters) {
        println!("The first letter is {}", first);
    } else {
        println!("The slice is empty.");
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1398033.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文读懂「Fine-tuning」微调

一、什么是微调&#xff1f; 1. 什么是微调&#xff1f; 微调是指在预训练模型&#xff08;Pre-trained model&#xff09;的基础上&#xff0c;针对特定任务或数据领域&#xff0c;对部分或全部模型参数进行进一步的训练和调整&#xff08;Fine Tune&#xff09;。预训练模型…

03 MyBatisPlus之条件构造器Wrapper+三个核心注解

2. 条件构造器 2.1 条件构造器作用 //创建一个查询条件构造器对象,所有条件都放进去 QueryWrapper<User> queryWrapper new QueryWrapper<>(); queryWrapper.eq("name", "John"); // eq添加等于条件 queryWrapper.ne("age", 30);…

伊恩·斯图尔特《改变世界的17个方程》波动方程笔记

主要是课堂的补充&#xff08;yysy&#xff0c;我觉得课堂的教育模式真有够无聊的&#xff0c;PPT、写作业、考试&#xff0c;感受不到知识的魅力。 它告诉我们什么&#xff1f; 小提琴琴弦上某个小段的加速度&#xff0c;与相邻段相对于该段的平均位移成正比。 为什么重要&…

初阶数据结构:顺序表

目录 1. 引子&#xff1a;线性表2. 简单数据结构&#xff1a;顺序表2.1 顺序表简介与功能模块分析2.2 顺序表的实现2.2.1 顺序表&#xff1a;存储数据结构的构建2.2.2 顺序表&#xff1a;初始化与空间清理&#xff08;动态&#xff09;2.2.3 顺序表&#xff1a;插入与删除数据2…

总结网络中的一些基本概念

1. IP地址 描述一个设备在网络上的位置&#xff0c;而且计算机是通过数字来描述IP地址的。例如&#xff08;生活中的地址&#xff09; 2. 端口号 描述一个主机上的哪个应用程序&#xff0c;有了IP可以确定主机&#xff0c;但是一个主机上可能有很多程序在使用网络&#xff0c;…

基于SpringBoot Vue自习室管理系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

Elasticsearch各种高级文档操作3

本文来记录几种Elasticsearch的文档操作 文章目录 初始化文档数据聚合查询文档概述对某个字段取最大值 max 示例对某个字段取最小值 min 示例对某个字段求和 sum 示例对某个字段取平均值 avg 示例对某个字段的值进行去重之后再取总数 示例 本文小结 初始化文档数据 在进行各种文…

ASP.NET Core 对象池化技术

写在前面 Microsoft.Extensions.ObjectPool 是 ASP.NET Core 基础结构的一部分&#xff0c;当对象的初始化成本较高&#xff0c;并且可能被频繁使用时&#xff0c;才适合采用对象池技术&#xff1b;被ObjectPool管理的对象不会进入垃圾回收&#xff0c;使用时通过由实例对象实…

【迅搜19】扩展(二)TNTSearch和JiebaPHP方案

扩展&#xff08;二&#xff09;TNTSearch和JiebaPHP方案 搜索引擎系列的最后一篇了。既然是最后一篇&#xff0c;那么我们也轻松一点&#xff0c;直接来看一套非常有意思的纯 PHP 实现的搜索引擎及分词方案吧。这一套方案由两个组件组成&#xff0c;一个叫 TNTSearch &#xf…

【0到1的设计之路】从C语言到二进制程序

C程序如何从源代码生成指令序列(二进制可执行文件) 预处理 -> 编译 -> 汇编 -> 链接 -> 执行 预处理 预处理 文本粘贴 #include <stdio.h> #define MSG "Hello \ World!\n" int main() {printf(MSG /* "hi!\n" */); #ifdef __riscvpr…

PE解释器之PE文件结构(二)

接下来的内容是对IMAGE_OPTIONAL_HEADER32中的最后一个成员DataDirectory&#xff0c;虽然他只是一个结构体数组&#xff0c;每个结构体的大小也不过是个字节&#xff0c;但是它却是PE文件中最重要的成员。PE装载器通过查看它才能准确的找到某个函数或某个资源。 一&#xff1…

2种数控棋

目录 数控棋1 数控棋2 数控棋1 棋盘&#xff1a; 初始局面&#xff1a; 规则&#xff1a; 规则&#xff1a;双方轮流走棋&#xff0c;可走横格、竖格、可横竖转弯&#xff0c;不可走斜格。每一步均须按棋所在格的数字走步数&#xff0c;不可多不可少。 先无法走棋的一方为…

如何有效防爬虫?一文讲解反爬虫策略

企业拥抱数字化技术的过程中&#xff0c;网络犯罪分子的“战术”也更难以觉察&#xff0c;并且这些攻击越来越自动化和复杂&#xff0c;也更加难以觉察。在众多攻击手段中&#xff0c;网络爬虫是企业面临的主要安全挑战。恶意爬虫活动可能导致数据滥用、盗窃商业机密等问题&…

ctfshow php特性(web89-web101)

目录 web89 web90 web91 web92 web93 web94 web95 web96 web97 web98 web99 web100 web101 php特性(php基础知识) web89 <?php include("flag.php"); highlight_file(_FILE_);if(isset($_GET[num])){$num$_GET[num];if(preg_match("/[0-9]/&…

ffmpeg 常用命令行详解

概述 ffmpeg 是一个命令行音视频后期处理软件 1. 裁剪命令 参数说明 -i 文件&#xff0c;orgin.mp3 为待处理源文件-ss 裁剪时间&#xff0c;后跟裁剪开始时间&#xff0c;或者开始的秒数-t 裁剪时间output.mp3 为处理结果文件 ffmpeg -i organ.mp3 -ss 00:00:xx -t 120 o…

Oracle 隐式数据类型转换

目录 Oracle类型转换规则&#xff1a; 看如下实验&#xff1a; 1、创建一张表&#xff0c;字段id的类型为number&#xff0c;id字段创建索引&#xff0c;插入一条测试数据 2、我们做如下查询&#xff0c;id的值设置为字符型的1 3、查看执行计划&#xff1a; Oracle类型转换…

MySQL之索引结构

索引概述 索引是帮助MySQL高效获取数据的数据结构&#xff08;有序&#xff09;。 在数据之外&#xff0c;数据库系统还维护着满足特定查找算法的数据结构&#xff0c;这些数据结构以某种方式引用&#xff08;指向&#xff09;数据&#xff0c;这样就可以在这些数据结构上实现…

JMeter实操入门之登录

JMeter实操入门之登录 前言初级-无变量的登录线程组取样器-HTTP请求 进阶-定义变量的登录用户定义的变量获取JSON返回的数据-tokentoken设置全局变量 前言 安装及环境配置教程可移步&#xff1a;JMeter安装与配置环境 本篇文章针对小白进一步的认识及运用JMeter&#xff0c;围绕…

从数据角度分析年龄与NBA球员赛场表现的关系【数据分析项目分享】

好久不见朋友们&#xff0c;今天给大家分享一个我自己很感兴趣的话题分析——NBA球员表现跟年龄关系到底大不大&#xff1f;数据来源于Kaggle&#xff0c;感兴趣的朋友可以点赞评论留言&#xff0c;我会将数据同代码一起发送给你。 目录 NBA球员表现的探索性数据分析导入Python…

ChatGPT与文心一言:AI助手之巅的对决

随着科技的飞速发展&#xff0c;人工智能助手已经渗透到我们的日常生活和工作中。 而在这个充满竞争的领域里&#xff0c;ChatGPT和文心一言无疑是最引人注目的两款产品。它们各自拥有独特的优势&#xff0c;但在智能回复、语言准确性、知识库丰富度等方面却存在差异。那么&am…