VueBloghyhero6

学习了下Rust写点语法总结

2024-05-30 / 2024-05-30 / 1061次浏览
trait可以包含方法签名(特质)是一种定义共享行为的机制
trait可以包含方法签名、关联常量或类型,允许不同类型实现这些方法或提供相关的常量或类型。通过实现trait,类型可以表明它们拥有trait中定义的行为,从而实现代码的重用和抽象
还有引用这个部分也很重要&表示不可变引用,&mut表示可变引用,
是否可变在这里很重要,或者说在 Rust 里很重要你要表明这个数据是可变的还是不可变的。引用也有借用的意思是一个意思。

还有一个好玩的语法解构效果Rust 和 JS 是不统一不一致的。就比如下面这段语法:

// Instantiate a `Point`
let point: Point = Point { x: 10.3, y: 0.4 };
// Make a new point by using struct update syntax to use the fields of our
// other one
let bottom_right = Point { x: 5.2, ..point };

在 JS 里面 point 会被结构扩展变成一个三项对象,但是在Rust里面,x:5.2 会被替换,然后y:0.4会被继承回来。
#![allow(dead_code)] 是 Rust 中的一个属性,用于隐藏未使用代码的警告。当你在代码中定义了一些未使用的函数或变量时,编译器会发出警告,可以使用这个属性来告诉编译器不要发出这些警告,对用调试开发阶段和在debug阶段的代码是很有帮助的。
#[derive(Debug)] 是 Rust 中的一个宏,用于自动生成实现Debug trait的代码,通过在结构体或枚举加上#[derive(Debug)] ,可以自动实现
Debug trait,从而可以使用{:?} 格式化输出调试信息。这样可以方便地打印结构体或枚举内容来方便调试代码,这也是输出打印的时候{:?}

解释一下这几种打印格式也行
{}: 这是最基本的占位符,用于默认的格式化输出,它会调用类型的Dispaly trait 来进行格式输出,适用于大多数类型。
{:?}: 这个占位符用于调试输出,会调用类型的Debug trait 来进行格式化输出,适用于大多数类型。
{:#?}: 这个占位符也用于调试输出,但是会以更加美观的方式输出,通常会带有缩进和换行,更适合查看复杂的数据结构。
列举一些新见识到的专有名词吧
枚举(Enum),变体(Variant),特质,切片

Rust还有一个特质就是在同一作用域内多次使用相同的变量名,每次声明都会创建一个新的变量,而不会影响之前的变量。

可以理解为再次声明同名变量shadowed_binding,这样就会继续遮蔽之前的同变量名形成变量阴影。

fn main() {
    let shadowed_binding = 1;

    {
        println!("before being shadowed: {}", shadowed_binding);

        // This binding *shadows* the outer one
        let shadowed_binding = "abc";

        println!("shadowed in inner block: {}", shadowed_binding);
    }
    println!("outside inner block: {}", shadowed_binding);

    // This binding *shadows* the previous binding
    let shadowed_binding = 2;
    println!("shadowed in outer block: {}", shadowed_binding);
}

在 Rust 中, use 关键字用于将一个路径(path)引入当前作用域,以便在代码中可以直接使用该路径中的内容,而无需每次完整地写出路径,
例如 use std::conver::Into; 引入了标准库中 std::convert::Into.

通过使用 use 关键字引入路径,可以使代码更简洁、易读,并且方便在代码里使用标准库或其他库的中的内容。增强可见性,其实说实话有点 想 import

还有就是Rust是要显式转换的,但是就是代码量很大,我是初学,但是文档上例子是给出这么多的。

use std::convert::Into;

#[derive(Debug)]
struct Number {
    value: i32,
}

impl Into<Number> for i32 {
    fn into(self) -> Number {
        Number { value: self }
    }
}

fn main() {
    let int = 5;
    // Try removing the type annotation
    let num: Number = int.into();
    println!("My number is {:?}", num);
}

Rust 作为一种系统语言类型转换控制更加的严格,不同于JavaScript的可以使用任意隐式转换,而在 Rust 中,为了避免潜在的类型错误和安全问题,类型转换需要更明确和安全。

对于数字类型转换,Rust 提供了一些内置的方法和 trait 来支持不同类型之间的转换,例如 as 关键字、From trait、Into trait 等。这些方法和 trait 可以帮助开发者在编写 Rust 代码时进行类型转换,同时保证类型的安全性和正确性。

#![allow(unreachable_code, unused_labels)] 表示编译器不产生报警信息并且不会报警。

unreachable_code:表示允许存在不可达代码,即编译器在分析代码时发现某些代码永远不会被执行到,但仍然允许这样的代码存在,但是在通常情况下不可达代码是一个编程错误,因为它表示代码存在逻辑错误或冗余代码。

unused_labels:表示的是允许存在未使用的标签,即定义了标签但未在代码中使用。标签通常用于循环或代码块中,用于标识特定的代码块或循环,如果定义了标签但是却没有使用,通常是认为不必要的。

在 rust 禁止存在冗余代码
所以在开头要加上
#![allow(unreachable_code, unused_labels)]

比如下面这段冗余代码

fn main() {
    'outer: loop {
        println!("Entered the outer loop");

        'inner: loop {
            println!("Entered the inner loop");

            // This would break only the inner loop
            //break;

            // This breaks the outer loop
            break 'outer;
        }

        println!("This point will never be reached");
    }

    println!("Exited the outer loop");
 }

上面这段代码中了 break 'outer; 下面的打印直接失效了跳出外部循环。
也就是说下面的这个println!("Exited the outer loop");根本打印不出来。
上面代码可以拿编译器去试试。

以及还有下面的示例代码,在Rust中,assert_eq! 是一个宏(macro),用于比较俩个值是否相等,并在断言失败时触发panic(运行时错误)。这个宏经常用于编写测试代码,以确保程序的某些部分按期工作。

assert_eq!(left, right);
fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2;
        }
    };

    assert_eq!(result, 20);
}

比如 在Rust 中创建一组类型向量, let mut names = vec!["Bob","Frank","Ferris"]
创建了一个可变的Vec<&str>类型的向量。 而 inter_mut() 是 Vec 类型的一个方法,用于返回一个可变迭代器,允许您以可变的方式遍历向量中每一个元素。具体的数组遍历迭代代码就是,

fn main() {
    let mut names = vec!["Bob", "Frank", "Ferris"];

    for name in names.iter_mut() {
        *name = match name {
            &mut "Ferris" => "There is a rustacean among us!",
            _ => "Hello",
        }
    }

    println!("names: {:?}", names);
}

根据 rust 的语言引用, 任何数组可修改都要加入mut,
所以上面的输入结果就是 names: ["Hello","Hello", "There is a rustacean among us!"]

它重新修改了数组。

关于for循环
for n in 1..101
这个数值不包括101 是 1 到 100

Rust 中需要显示使用 & ref ref mut 等关键字创建引用,因为 JS 是动态类型,和垃圾回收机制,所以没法显示的去标注类型,在 JS 中当我们传递对象或数组时实际是将对象或数组的引用传递给函数,而不是辅助整个对象或者数组。

然后 let reference = &4 和 let reference = 4 这俩行代码有着不同的含义和效果:

let reference = &4 创建一个引用类型,一个指向整数4的不可变引用,意味着 reference 变量持有整数4的地址,而不是直接持有整数值本身,这个引用可以访问整数4的值,但不能修改它。

引用是可以绑定的但是引用也是可以解除的

let reference = &4
match *reference {
  val => println!("Got a value via dereferencing: {:?}", val)
}

上面的代码 match 解除了引用,并且把值指向了val,
*reference 对引用进行解引用,获取引用所指向的值,即整数4

在match 中, 使用模式匹配,将解引用后的值 4 绑定到了 变量 val。