乐趣区

关于javascript:聊聊Rust-运算符

运算符 用于对数据执行一些操作。被运算符执行操作的数据咱们称之为操作数。上面通过本文给大家介绍 Rust 运算符的相干常识,感兴趣的敌人一起看看吧

目录
一元运算符
二元运算符
算数操作符
位运算符
惰性 boolean 运算符
比拟运算符
类型转换运算符
重载运算符
格式化字符串

一元运算符
顾名思义,一元操作符是专门对一个 Rust 元素进行操作的运算符,次要包含以下几个:

  • :取负,专门用于数值类型。实现了 std::ops::Neg。
  • :解援用。实现了 std::ops::Deref 或 std::ops::DerefMut。
    !:取反。例如 !false 相当于 true。有意思的是,如果这个操作符对数字类型应用,会将其每一位都置反!也就是说,对一个 1u8 进行 ! 操作,将失去一个 254u8。实现了 std::ops::Not。
    & 和 &mut:租借,borrow。向一个 owner 租借其使用权,别离租借一个只读使用权和读写使用权。

二元运算符

算数操作符

  • :加法。实现了 std::ops::Add。
    -:减法。实现了 std::ops::Sub。
  • :乘法。实现了 std::ops::Mul。
    /:除法。实现了 std::ops::Div。
    %:取余。实现了 std::ops::Rem。

位运算符
&:与操作。实现了 std::ops::BitAnd。
|:或操作。实现了 std::ops::BitOr。
-^:异或。实现了 std::ops::BitXor。
<<:左移运算符。实现了 std::ops::Shl。

:右移运算符。实现了 std::ops::Shr。

惰性 boolean 运算符
逻辑运算符有三个,别离是 &&、|| 和!。其中前两个叫做惰性 boolean 运算符,之所以叫这个名字,是因为在 Rust 中也会呈现其余类 C 语言的逻辑短路问题,所以取了这么一个名字。其作用和 C 语言里的截然不同。不过不同的是,Rust 里这个运算符只能用在 bool 类型上。

比拟运算符
比拟运算符实际上也是某些 trait 的语法糖,不过比拟运算符所实现的 trait 只有 2 个:std::cmp::PartialEq 和 std::cmp::PartialOrd。

其中,== 和!= 实现的是 PartialEq,<、>、>= 和 <= 实现的是 PartialOrd。

规范库中,std::cmp 这个 mod 下有 4 个 trait,而且直观来看 Ord 和 Eq 岂不是更好?但 Rust 对于这 4 个 trait 的解决是很明确的。因为在浮点数有一个非凡的值叫 NaN,这个值示意未定义的一个浮点数。在 Rust 中能够用 0.0f32 / 0.0f32 来求得其值,这个数是一个都确定的值,但它示意的是一个不确定的数,那么 NaN != NaN 的后果是啥?规范库通知咱们是 true。但这么写有不合乎 Eq 定义里的 total equal(每位一样两个数就一样)的定义。因而有了 PartialEq 这么一个定义,NaN 这个状况就给它特指了。

为了普适的状况,Rust 的编译器就抉择了 PartialOrd 和 PartialEq 来作为其默认的比拟符号的 trait。

类型转换运算符
这个看起来并不算个运算符,因为它是个单词 as。就是相似于其余语言中的显示转换了。

fn avg(vals: &[f64]) -> f64 {let sum: f64 = sum(vals);
    let num: f64 = len(vals) as f64;
    sum / num
}

重载运算符
下面说了很多 trait,就是为了运算符重载。Rust 是反对运算符重载的。更具体的局部,会在后续章节中介绍。这是一个例子:

use std::ops::{Add, Sub};
 
\#[derive(Copy, Clone)]
struct A(i32);
 
impl Add for A {
    type Output = A;
    fn add(self, rhs: A) -> A {A(self.0 - rhs.0)
    }
}
 
impl Sub for A {
    type Output = A;
    fn sub(self, rhs: A) -> A{A(self.0 + rhs.0)
    }
}
 
fn main() {let a1 = A(10i32);
    let a2 = A(5i32);
    let a3 = a1 + a2;
    println!("{}", (a3).0);
    let a4 = a1 - a2;
    println!("{}", (a4).0);
}
   Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `yourpath\hello_world\target\debug\hello_world.exe`
5
15

格式化字符串
Rust 采取了一种相似 Python 外面 format 的用法,其外围组成是 5 个宏和两个 trait:
format!、format_arg!、print!、println!、write!和 Debug、Display。

之前在 hello_world 里曾经应用了 print! 或者 println! 这两个宏,然而最外围的是 format!,前两个宏只不过是将 format! 的后果输入到 console 而已。

先来剖析一个 format! 的利用:

fn main() {let s = format!("明天是 {0} 年{1}月 {2} 日, {week:?}, 气温{3:>0width$} ~ {4:>0width$} 摄氏度。",
        2016, 11, 24, 3, -6, week = "Thursday", width = 2);
 
    print!("{}", s);
}

能够看到,format! 宏调用的时候参数能够是任意类型,而且能够 position 参数和 key-value 参数混合应用。但要留神一点,key-value 的值只能呈现在 position 值之后并且不占用 position。比方把下面的代码改变一下:

fn main() {let s = format!("明天是 {0} 年{1}月 {2} 日, {week:?}, 气温{3:>0width$} ~ {4:>0width$} 摄氏度。",
        2016, 11, 24, week = "Thursday", 3, -6, width = 2);
 
    print!("{}", s);
}

这样将会报错:

Compiling hello_world v0.1.0 (yourpath/hello_world)
error: expected ident, positional arguments cannot follow named arguments
–> main.rs:3:42
|
3 | 2016, 11, 24, week = “Thursday”, 3, -6, width = 3);
| ^

error: aborting due to previous error

error: Could not compile hello_world.

还须要留神的是,参数类型必须要实现 std::fmtmod 下的某些 trait。比方原生类型大部分都实现了 Display 和 Debug 这两个宏,整数类型还额定实现了 Binary,等等。

能够通过 {:type} 的形式取调用这些参数。比方:

format!(":b", 2); // 调用 `Binary` trait
 
format!(":?", "hello"); // 调用 `Debug`

如果 type 为空的话默认调用 Display。

冒号 : 前面还有更多参数,比方下面代码中的 {3:>0wth$} 和 {4:>0wth$}。首先 > 是一个语义,它示意的是生成的字符串向右对齐,于是下面的代码失去了 003 和 -06 这两个值。与之绝对的还有向左对齐 < 和居中 ^。

接下来 0 是一种非凡的填充语法,他示意用 0 补齐数字的空位,而 wth& 示意格式化后的字符串长度。它能够是一个准确的长度数值,也能够是一个以 $ 为结尾的字符串,$ 后面的局部能够写一个 key 或者一个 position。

还要留神的是,在 wth 和 type 之间会有一个叫精度的区域,他们的示意通常是以 . 开始的,比方.4 示意小数点后 4 位精度。最让人糟心的是,任然能够在这个地位援用参数,只须要个下面 wth 一样,用.N$ 来示意一个 position 的参数,只是就是不能引用 key-value 类型的。比方:

fn main() {// Hello {arg 0 ("x")} is {arg 1 (0.01) with precision specified inline (5)}
    println!("Hello {0} is {1:.5}", "x", 0.01);
 
    // Hello {arg 1 ("x")} is {arg 2 (0.01) with precision specified in arg 0 (5)}
    println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
 
    // Hello {arg 0 ("x")} is {arg 2 (0.01) with precision specified in arg 1 (5)}
    println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
}

将输入:

Hello x is 0.01000
Hello x is 0.01000
Hello x is 0.01000

这一位还有一个非凡的用法,那就是 .*,它不示意一个值,而是示意两个值。第一个值示意准确的位数,第二个值标示意这个值自身。例如:

fn main() {// Hello {next arg ("x")} is {second of next two args (0.01) with precision
    //                          specified in first of next two args (5)}
    println!("Hello {} is {:.*}",    "x", 5, 0.01);
 
    // Hello {next arg ("x")} is {arg 2 (0.01) with precision
    //                          specified in its predecessor (5)}
    println!("Hello {} is {2:.*}",   "x", 5, 0.01);
 
    // Hello {next arg ("x")} is {arg "number" (0.01) with precision specified
    //                          in arg "prec" (5)}
    println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01);
}

这个例子将输入:

Hello x is 0.01000
Hello x is 0.01000
Hello x is 0.01000

能够在规范库文档查看更多 format! 的阐明。

到此这篇对于 Rust 运算符的文章就介绍到这了, 更多相干 Rust 运算符内容请搜寻 segmentfault 以前的文章或持续浏览上面的相干文章心愿大家当前多多反对 segmentfault!

退出移动版