返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >聊聊Rust 运算符
  • 198
分享到

聊聊Rust 运算符

2024-04-02 19:04:59 198人浏览 安东尼
摘要

目录一元运算符二元运算符算数操作符位运算符惰性 boolean 运算符比较运算符类型转换运算符重载运算符格式化字符串一元运算符 顾名思义,一元操作符是专门对一个 Rust 元素进行操

一元运算符

顾名思义,一元操作符是专门对一个 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::PartialEqstd::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 的编译器就选择了PartialOrdPartialEq来作为其默认的比较符号的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!DebugDisplay

之前在 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。比如原生类型大部分都实现了 DisplayDebug这两个宏,整数类型还额外实现了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 运算符内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 聊聊Rust 运算符

本文链接: https://lsjlt.com/news/157030.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 聊聊Rust 运算符
    目录一元运算符二元运算符算数操作符位运算符惰性 boolean 运算符比较运算符类型转换运算符重载运算符格式化字符串一元运算符 顾名思义,一元操作符是专门对一个 Rust 元素进行操...
    99+
    2024-04-02
  • 聊聊C++ 运算符重载知识
    前言 1.运算符重载是一种形式的C++多态。 2.重载运算符可以使代码看起来更加自然。 回顾类 在正常构造类的时候,有些成员方法可以不用写出来,例如在这样一个表示时间的类中,拷贝构造...
    99+
    2024-04-02
  • 聊聊PHP中的 === 运算符为什么比 == 快
    在上一篇《聊聊PHP中require_once()函数为什么不好用》中给大家介绍了PHP中require_once()为什么不好用的原因,感兴趣的朋友可以去阅读了解一下~ 那么本文将...
    99+
    2024-04-02
  • 聊聊C语言中sizeof运算符的一个陷阱
    sizeof运算符通常用于获取变量或类型所占内存的大小(单位是字节) #include <stdio.h> struct D{ char a; int...
    99+
    2022-11-13
    c语言程序运算符sizeof sizeof c语言 C语言sizeof函数
  • 详细聊聊React源码中的位运算技巧
    目录前言几个常用位运算按位与(&)按位或(|)按位非(~)标记状态优先级计算总结前言 这两年有不少朋友和我吐槽React源码,比如: 调度器为什么用小顶堆这种数据结...
    99+
    2024-04-02
  • 聊聊Python中的浮点数运算不准确问题
    大家好,老 Amy 来了。之前就意识到一个问题,但是最近又有朋友提出来了,所以就想着干脆记录下来,分享给大家叭~ 啥问题呢?请看题: 也就是说,需要大家计算1.1-1的值,很多朋友...
    99+
    2024-04-02
  • 聊聊golang = =符号的用途
    Golang,或者叫作 Go 编程语言,是一种由 Google 开发的静态类型、并发型、编译型的编程语言,它被广泛应用于后端服务开发、网络应用开发以及云计算领域。Golang 是一种相对年轻的编程语言,它于 2009 年首次推出,但它已经成...
    99+
    2023-05-14
  • Vue3学习:聊聊组件中怎么使用布尔运算
    (学习视频分享:vuejs入门教程、编程基础视频)同学们大家好,作者又来输出内容了,本文的主要内容是布尔运算。可能不少小伙伴们第一反应是咱们 Javascript 中的 true 和 false,是的没错,它们都是布尔值,但是布尔运算却远不...
    99+
    2023-05-14
    布尔运算 组件 前端 JavaScript Vue.js
  • 聊聊Java中的Native修饰符
    目录Native修饰符的使用native主要用于方法上说明举例Native修饰的方法到底有什么用处什么是NativeMethod为什么要使用NativeMethodJVM怎样使Nat...
    99+
    2024-04-02
  • 浅谈Rust += 运算符与 MIR 应用
    目录赋值表达式的求值顺序MIR单一实现下的强转两阶段借用的参与+= 运算符与 MIR 应用 本文 += 运算符部分整理自 Why does += require manual der...
    99+
    2023-01-31
    Rust += 运算符 Rust MIR 应用 Rust 运算符
  • 简单聊聊TypeScript只读修饰符
    目录前言只读函数参数如何更改函数只读类属性只读索引总结前言 在Typescript 2.0中,引入了readonly关键字,可以对类中的属性进行修饰,作用是:该属性被readonly...
    99+
    2024-04-02
  • 聊聊Vue中的计算属性computed
    一、计算属性computed1.1.什么是计算属性computed⭐⭐ computed 是基于它的依赖缓存,只有在它的相关依赖发生改变时才会进行更新。官方文档是这样说的:对于任何包含响应式数据的复杂逻辑,你都应该使用计算属性。 (学习视频...
    99+
    2022-11-22
    vue3 vue.js Vue
  • 聊聊PHP部署和运行的方法
    PHP是一门流行的服务器端编程语言,广泛应用于Web开发。在开始编写PHP程序之前,需要先将PHP部署和运行起来。本文将介绍PHP部署和运行的方法。安装PHP首先需要将PHP安装到你的计算机上。可以从PHP官网下载PHP安装包,选择适合你的...
    99+
    2023-05-14
  • 聊聊python逻辑运算及奇怪的返回值(not,and,or)问题
    首先,‘and’、‘or’和‘not’的优先级是not>and>or。 同一优先级从左往右计算。 ...
    99+
    2024-04-02
  • 聊聊Python中的@符号是什么意思
    Python中的@符号是装饰器的意思。Python中装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象(函数的指针...
    99+
    2024-04-02
  • 简单聊聊Java程序中的换行符
    目录常见的换行符\r\n和\n的区别换行符的解析小结常见的换行符 Java程序中的换行符一般使用“\n”表示,它是一个转义字符,表示换行符。根据操作系统的不同...
    99+
    2023-03-21
    Java 换行符使用 Java换行符
  • 聊聊php中箭头符号(->)的用法
    PHP箭头(->)是一种用于对象访问的符号。在PHP中,对象是一组属性和方法的集合。箭头符号允许开发人员访问和操作这些属性和方法。在PHP中,对象可以通过实例化类创建,然后使用箭头符号来访问对象的属性和方法。例如,下面是一个简单的PH...
    99+
    2023-05-14
    php 箭头
  • 简单聊聊Golang中defer预计算参数
    目录什么是deferGo语言defer预计算参数总结什么是defer defer用来声明一个延迟函数,把这个函数放入到一个栈上, 当外部的包含方法return之前,返回参数到调用方法...
    99+
    2024-04-02
  • 深入聊一聊虚拟DOM与diff算法
    目录虚拟DOM与diff算法snabbdom环境搭建虚拟DOM和h函数diff算法patch函数patchVnode函数updateChildren函数v-for中key作...
    99+
    2024-04-02
  • 详细聊一聊algorithm中的排序算法
    目录前言一、algorithm是什么?二、有哪些排序算法?sortrandom_shufflemergereverse总结前言 雨下不停,爱意难眠,说一下algorithm中的几个排...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作