Rust变量和类型

【一起学Rust 基础篇】Rust基础——变量和数据类型_rust 变量指定数据类型 以上就是本期所要讲述的内容了。本期主要讲了变量的定义变量的可变性基本变量类型整型网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。需要这份系统化资料的朋友,可以戳这里获取一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长! 阅读详情

我们将探讨Rust程序的基本构建块,如变量和类型。我们将讨论基本类型的变量,它们是否需要声明类型,以及变量的作用域。不可变性,作为Rust安全策略的基石之一,也将被讨论和展示。

我们将涵盖以下主题:

  • 注释
  • 全局常量
  • 值和基本类型
  • 变量绑定值
  • 变量的作用域和遮蔽
  • 类型检查和转换
  • 表达式
  • 栈和堆

我们的代码示例将围绕构建一个基于文本的游戏 Monster Attack。

注释

理想情况下,程序应通过使用描述性的变量名和易于阅读的代码自我记录,但总是存在需要额外注释程序结构或算法的情况。Rust遵循C语言的惯例,有:

  • // 行注释;在 // 之后的行内所有内容都是注释,不会被编译
  • /* / 块注释或多行注释;/ 和 */ 之间的所有内容都不会被编译

然而,Rust推荐的风格是只使用 // 注释,即使是多行,如下代码所示:

fn main() { 
  // 这里开始执行游戏。 
  // 我们首先打印欢迎信息: 
  println!("欢迎来到游戏!"); 
}  

只有在注释掉代码时才使用 /* */ 注释。

Rust还有一个文档注释 ///,在需要为客户和开发者提供官方文档的大型项目中很有用。这些注释必须出现在项目(如函数)之前的单独一行上,以记录该项目。在这些注释中,您可以使用Markdown格式语法(参见https://en.wikipedia.org/wiki/Markdown)。

这是一个文档注释:

fn main() { 
}  

我们将在后续代码片段中看到更多 /// 的相关用法。rustdoc工具可以将这些注释编译成项目文档。

全局常量

通常,应用程序需要一些实际上是常量的值,这意味着它们在程序运行过程中不会改变。例如,在我们的游戏中,游戏名称Monster Attack可能是一个常量,最大健康量100也可能是一个常量。我们必须能够在main()函数或程序中的任何其他函数中使用它们,因此它们被放置在代码文件的顶部。它们存在于程序的全局作用域中。这样的常量是用关键字static声明的,如下所示:

static MAX_HEALTH: i32 = 100; 
static GAME_NAME: &str = "Monster Attack"; 
 
fn main() { 
}  

常量的名称必须为大写,可以使用下划线分隔词组。它们的类型也必须指明;变量MAX_HEALTH是一个32位整数(i32),而变量GAME_NAME是字符串(str)类型。正如我们将进一步讨论的,变量的类型声明方式与此完全相同,尽管当编译器能够从代码上下文推断出类型时,这通常是可选的。

记住,Rust是一种低级语言,所以许多事情必须详细指定。& 是对某物的引用(它包含其内存地址),这里是字符串的引用。

编译器给出的警告如下所示:

warning: static item is never used: `MAX_HEALTH`, #[warn(dead_code)] on by default  

这个警告不会阻止编译,所以在这个阶段,我们可以编译成可执行文件constants1.exe。但编译器是对的;这些对象在程序代码中从未被使用(它们被称为死代码),所以,在一个完整的程序中,要么使用它们,要么抛弃它们。

Rust开发者需要一段时间才能开始将Rust编译器视为朋友,而不是一个吐出错误和警告的烦人机器。只要你在编译器输出的最后看到这个信息,error: aborting due to previous errors,就不会产生(新的)已编译可执行文件。但请记住,更正错误可以消除运行时问题,因此这可以节省您追踪烦人错误所浪费的大量时间。错误消息通常伴有有关如何消除错误的有用说明。即使是警告也可以指出代码中的缺陷。Rust甚至会警告我们在接下来的代码中声明但未使用的内容,如未使用的变量、函数、导入的模块等。如果我们使一个变量可变(意味着它的值可以被改变)而它不应该这样,或者代码没有得到执行时,它甚至会警告我们!编译器做得如此出色,以至于当你消除所有错误和警告时,你的程序很可能会正确运行!

除了静态值,我们还可以使用简单的常量值,其值永不改变。常量总是必须被类型化,如下所示:

const MYPI: f32 = 3.14; 

编译器会自动在代码中的每个地方替换常量的值。

使用字符串插值进行打印

使用变量的一个明显方法是打印出它们的值,如下所示:

static MAX_HEALTH: i32 = 100; 
static GAME_NAME: &str = "Monster Attack"; 
const MYPI: f32 = 3.14; 
 
fn main() { 
  println!("你正在玩的游戏叫做 {}。", GAME_NAME); 
  println!("你开始时有 {} 点健康值。", MAX_HEALTH); 
}  

这会产生如下输出:

你正在玩的游戏叫做 Monster Attack。
你开始时有 100 点健康值。 

println! 宏的第一个参数是包含占位符 {} 的字面格式字符串。逗号后的常量或变量的值被转换为字符串并放在其位置。可以有多个占位符,并且可以按顺序编号,以便重复使用,如下代码所示:

println!("在游戏 {0} 中你开始时有 {1} % 的健康值,是的,你没看错:{1} 点!", GAME_NAME, MAX_HEALTH); 

这将产生以下输出:

在游戏 Monster Attack 中你开始时有 100 % 的健康值,是的,你没看错:100 点!

占位符也可以包含一个或多个命名参数,如下所示:

println!("你有 {points} % 的健康值", points = 70); 

这将产生以下输出:

你有 70 % 的健康值  

特殊的格式化方式可以在冒号 (😃 后的 {} 内指定,可选地加上位置前缀,如下所示:

println!("MAX_HEALTH 的十六进制表示为 {:x}", MAX_HEALTH); // 

这会产生如下输出:64

println!("MAX_HEALTH 的二进制表示为 {:b}", MAX_HEALTH);   // 

这会产生如下输出:1100100

println!("数字二的二进制表示是 {0:b}", 2);   // 

这会产生如下输出:10

println!("π 的浮点表示是 {:e}", PI);  // 

这会产生如下输出:3.14e0。

以下是格式化的可能性:

  • o:表示八进制
  • x:表示小写的十六进制
  • X:表示大写的十六进制
  • p:表示指针
  • b:表示二进制
  • e:表示小写的指数表示法
  • E:表示大写的指数表示法
  • ?:用于调试目的

format! 宏的参数与 println! 宏相同,并且工作方式相同,但它返回一个字符串而不是打印输出。

有关所有可能性的概览,请参阅 http://doc.rust-lang.org/std/fmt/ 。

值和基本类型

已初始化的常量具有值。值存在于不同的类型中:70 是一个整数,3.14 是一个浮点数,Z 和 θ 是字符类型。字符是 Unicode 值,每个占用四个字节的内存。Godzilla 是 &str 类型的字符串(默认为 Unicode UTF8),true 和 false 是布尔值类型。整数可以用不同的格式书写:

  • 十六进制格式,以 0x 开头,如 0x46 表示 70。

  • 八进制格式,以 0o 开头,如 0o106 表示 70。

  • 二进制格式,以 0b 开头,如 0b1000110。

  • 为了可读性,可以使用下划线,如 1_000_000。有时编译器会要求您更明确地用后缀指示数字的类型,例如(u 或 i 后的数字表示使用的内存位数,即:8、16、32 或 64)。

  • 数字 10usize 表示机器字长的无符号整数(usize),可以是以下类型之一:u8、u16、u32、u64。

  • 数字 10isize 表示机器字长的有符号整数(isize),可以是以下类型之一:i8、i16、i32、i64

  • 在上述情况下,在 64 位操作系统上,usize 实际上是 u64,isize 等同于 i64。

  • 数字 3.14f32 表示 32 位浮点数。

  • 数字 3.14f64 表示 64 位浮点数。

  • 如果没有给出后缀,数值类型 i32 和 f64 是默认值,但在这种情况下,为了区分它们,您必须用 .0 结尾表示 f64 值,如:

let e = 7.0; 

一般来说,建议指明具体类型。

Rust 在不同运算符及其优先级方面与其他 C 类语言相似。然而,请注意,Rust 没有增量(++)或减量(–)运算符。使用 == 比较两个值是否相等,使用 != 测试它们是否不同。

甚至还有零大小的空值 (),它是所谓的单位类型 () 的唯一值。当一个表达式或函数没有返回任何值(无值)时,它用于指示返回值,例如仅向控制台打印的函数。() 不等同于其他语言中的 null 值;() 是无值,而 null 是一个值。

查阅 Rust 文档

找到关于 Rust 主题更详细信息的最快方式是浏览到标准库的文档页面,网址为 http://doc.rust-lang.org/std/。

在左侧,你可以找到所有可用的 crate 列表,你可以浏览以获取更多详情。但最有用的是顶部的搜索框:输入几个字母或一个词,就能得到许多有用的参考。

img

变量绑定值

在 Rust 中,我们不能把所有的值都存储为常量。这不是一个好的选择,因为常量与程序的生命周期一样长,而且不能改变,我们经常需要改变值。我们可以通过使用 let 绑定将一个值绑定到变量。

fn main() { 
  let energy = 5; // 值 5 被绑定到变量 energy 
}  

与 Python 或 Go 等许多其他语言不同,这里需要使用分号 ; 来结束语句。否则,编译器会抛出错误,如下:

error: expected one of `.`, `;`, or an operator, found `}`

我们也只想在程序的其余部分使用绑定时才创建绑定,但不用担心,Rust 编译器会警告我们。警告如下:

values.rs:2:6: 2:7 warning: unused variable: `energy`, #[warn(unused_variables)] on by default

出于原型设计目的,你可以通过在变量名前加一个下划线 _ 来抑制该警告,如 let _energy = 5; 通常 _ 用于我们不需要的变量。

请注意,在上述声明中我们没有指明类型。Rust 会推断 energy 变量的类型是整数,这是由 let 绑定触发的。如果类型不明显,编译器会在代码上下文中搜索变量获取值的地方或它的使用方式。

但是提供类型提示,如 let energy = 5u16; 也是可以的;这样,你就通过指明 energy 的类型(在这个例子中是两字节无符号整数)来帮助编译器。

我们可以通过在表达式中使用变量 energy 来使用它,例如将其分配给另一个变量,或打印它:

let copy_energy = energy; 
println!("Your energy is {}", energy););  

以下是其他一些声明:

let level_title = "Level 1"; 
let dead = false; 
let magic_number = 3.14f32; 
let empty = ();  // 单位类型 () 的值  

变量 magic_number 的值也可以写作 3.14_f32;_ 用来分隔数字和类型以提高可读性。

声明可以替代同一变量的先前声明。考虑如下语句:

let energy = "Abundant"; 

它现在将变量 energy 绑定到类型为字符串的值 Abundant。旧声明不再能使用,其内存被释放。

可变与不可变变量

假设我们吞下一个健康包,能量值提升到25。但是,如果我们像下面这样给变量 energy 赋值:

energy = 25;

我们会收到如下错误:

error: re-assignment of immutable variable `energy`.

这里出了什么问题?

好吧,Rust 在这里运用了程序员的智慧:很多bug都来自无意或错误的变量更改,所以除非你有意允许,否则不要让代码更改值!

在 Rust 中,变量默认是不可变的,这与函数式语言非常相似(在纯函数式语言中,甚至不允许可变性)。

如果你想要一个可变变量,因为它的值可以在代码执行期间更改,你必须明确地使用 mut 关键字来指示,例如:

  let mut fuel = 34; 
  fuel = 60;  

仅仅声明一个变量 let n; 也是不够的。我们会收到如下错误:

error: type annotations needed, consider giving `energy2` a type, cannot infer type for `_`

确实,编译器需要一个值来推断其类型。

我们可以通过给变量 n 赋一个值来提供这个信息,比如 n = -2; 但正如错误消息所说,我们也可以这样指明其类型:

  let n: i32; 

或者:

let n: i32 = -2; // `n` 是一个类型为 `i32` 和值为 `-2` 的绑定

类型(这里是 i32)跟在变量名后面,后面跟一个冒号 :(我们已经为全局常量展示过了),可选地跟一个初始化。通常类型是这样指示的——n: T,其中 n 是一个变量,T 是一个类型,它读作,变量 n 是 T 类型的。所以,这与 C 或 C++、Java 或 C# 中的做法相反,那里会写成 Tn。

对于基本类型,这也可以简单地用后缀来做,如下所示:

let x = 42u8; 
let magic_number = 3.14f64;  

尝试使用未初始化的变量会导致如下错误:

error: use of possibly uninitialized variable

局部变量必须在使用前初始化,以防止未定义行为。当编译器在你的代码中无法识别一个名字(例如,一个函数名)时,你会得到如下错误:

error: not found in this scope error

这很可能只是一个打字错误,但它在编译早期就被捕捉到了,而不是在运行时!

变量的作用域和隐藏

在程序 bindings.rs 中定义的所有变量都有局部作用域,由函数的 { } 界定,这里恰好是 main() 函数,但这适用于任何函数。在结束的 } 之后,它们就超出了作用域,它们的内存分配就被释放了。

我们甚至可以在函数内部通过定义一个代码块来创建一个更有限的作用域,代码块是包含在一对大括号 { } 内的所有代码,如下面的代码片段:

fn main() { 
  let outer = 42; 
   { // 代码块开始 
        let inner = 3.14; 
        println!("区块变量:{}", inner); 
        let outer = 99; // 遮蔽了第一个 outer 变量 
        println!("区块变量 outer:{}", outer); 
    } // 代码块结束 
    println!("外部变量:{}", outer); 
}  

前面的代码输出如下:

    区块变量:3.14
    区块变量 outer:99
    外部变量:42 

在块中定义的变量(如 inner)只在该块内部被知道。块中的变量也可以与外围作用域中的变量同名(如 outer),它被块中的变量替换(隐藏)直到块结束。当你尝试在块之后打印 inner 时,你期望会发生什么?试试看。

为什么你会想要使用一个代码块?在 表达式 部分,我们将看到一个代码块可以返回一个值,这个值可以用 let 绑定绑定到一个变量。代码块也可以为空 { }。

类型检查和转换

Rust 需要知道变量的类型,因为这样它可以在编译时检查它们只能按照它们的类型允许的方式使用。这样程序就是类型安全的,可以避免一整类的bug。

这也意味着我们不能在变量的生命周期内改变它的类型,因为静态类型,例如,以下代码片段中的变量 score 不能从整数变为字符串:

// 警告:这段代码不工作! 
fn main() { 
let score: i32 = 100; 
score = "YOU WON!" 
}  

这样,我们就会得到编译器错误,如下:

error: mismatched types: expected i32, found reference

然而,我被允许写成这样:

let score = "YOU WON!"; 

Rust 允许我重新定义变量;每个 let 绑定都创建一个新的变量 score,它隐藏了之前的变量,旧变量从内存中被释放。这实际上是非常有用的,因为变量默认是不可变的。

在 Rust 中不定义使用 + 拼接字符串(如以下代码中的 players):

let player1 = "Rob"; 
let player2 = "Jane"; 
let player3 = player1 + player2;  

这样我们会得到一个错误,说明如下:

error: binary operation `+` cannot be applied to type `&str`

在 Rust 中,你可以使用 to_string() 方法将值转换为 String 类型,像这样:

let player3 = player1.to_string() + player2; 

或者,你可以使用 format! 宏:

let player3 = format!("{}{}", player1, player2); 

在这两种情况下,变量 player3 的值都是 RobJane。

让我们看看当你将一个变量的值从一个类型分配给另一个不同类型的变量时会发生什么:

// 参见第2章/code/type_conversions.rs 
fn main() { 
  let points = 10i32; 
  let mut saved_points: u32 = 0; 
   saved_points = points; // 错误! 
}  

这同样是不允许的,因此,我们得到了同样的错误,如下:

error: mismatched types: expected u32, found i32

为了实现最大化的类型检查,Rust 不允许像 C++ 那样自动(或隐式)转换一个类型到另一个类型,从而避免了许多难以发现的bug。例如,当将一个 f32 值转换为 i32 值时,小数点后的数字会丢失;如果自动进行,这可能会导致错误。

然而,我们可以用关键字 as 做一个显式转换(也叫做类型转换),如下:

saved_points = points as u32; 

当变量 points 包含一个负值时,转换后会丢失符号。同样地,当从更宽的值如浮点数转换为整数时,小数部分会被截断。看下面的例子:

  let f2 = 3.14; 
  saved_points = f2 as u32; // 这里截断为值 3  

此外,值必须能够转换到新类型,例如字符串不能转换为整数:

  let mag = "Gandalf"; 
   saved_points = mag as u32; //  

这会导致如下错误:

error: non-scalar cast:`&str`as`u32`

别名

有时给现有类型一个新的、更具描述性或更简短的名称是很有用的。这是通过关键字 type 来完成的,如下面的例子,我们需要一个特定的(但大小有限的)变量来表示 MagicPower:

type MagicPower = u16; 
 
fn main() { 
  let mut run: MagicPower = 7800; 
}  

类型名称以大写字母开头,名称的每个单词部分也是如此。

当我们将值 7800 改为 78000 时会发生什么?编译器通过以下警告检测到这一点:

warning: literal out of range for u16

表达式

Rust 是一个以表达式为中心的语言,这意味着大多数代码片段实际上是表达式,也就是说,它们计算一个值并返回该值。然而,单独的表达式并不构成有意义的代码;它们必须被用在语句中。

如下的 let 绑定是声明语句;它们不是表达式:

let a = 2;    // a 绑定到 2 
let b = 5;    // b 绑定到 5 
let n = a + b;   // n 绑定到 7  

但是,这里的 a + b 是一个表达式,如果我们省略末尾的分号,结果值(这里是值 7)就会返回。这通常在函数需要返回其值时使用(见下一章的例子)。以分号结束的表达式 a + b; 抑制了这种行为,从而丢弃了返回值,使其成为返回单位值 () 的表达式语句。

代码通常是一系列语句,每个语句在一行代码上,Rust 需要知道语句何时结束,这就是为什么几乎每行 Rust 代码都以分号结束。

你认为 m = 42; 是什么?它不是绑定,因为没有 let 绑定(那应该在之前的代码行发生)。这是一个返回单位值 () 的表达式。

如 let p = q = 3; 这样的复合绑定在 Rust 中是不允许的,它返回以下错误:

error: unresolved name q

然而,你可以像这样链接 let 绑定:

let mut n = 0; 
let mut m = 1; 
let t = m; m = n; n = t; 
println!("{} {} {}", n, m, t); //  

这会输出:1 0 1

代码块也是一个表达式,如果我们省略分号,它返回其最后一个表达式的值。例如,在以下代码片段中,n1 获得值 7,但 n2 没有获得值(或者说,获得了单位值 ()),因为第二个块的返回值被抑制了:

let n1 = { 
let a = 2; 
let b = 5; 
a + b   // <-- 没有分号! 
}; 
  println!("n1 是:{}", n1);  // 打印:n1 是 7 
  let n2 = { 
    let a = 2; 
    let b = 5; 
    a + b; 
  }; 
  println!("n2 是:{:?}", n2);  // 打印:n2 是 ()  

块中声明的变量 a 和 b 只在该块存在期间存在,它们对该块是局部的。注意,块的闭合大括号后面的分号 }; 是必需的。要打印单位值 (),我们需要使用 {:?} 作为格式指定符。

栈和堆

因为在 Rust 中内存分配非常重要,我们必须对正在发生的事情有一个清晰的心理图像。一个程序的内存被分为栈内存和堆内存部分;要了解这些概念的更多背景,请访问 What and where are the stack and heap?。

像数字(如图中的 32)、字符或真或假值这样的原始值存储在栈上,但可能增长大小的更复杂对象的值存储在堆内存中。堆值由栈上的变量引用,该变量包含堆上对象的内存地址。

img

虽然栈的大小是有限的,但堆的大小可以根据需要的空间增长。

假设我们运行以下程序并尝试可视化程序的内存:

let health = 32; 
let mut game = "Space Invaders";  

值存储在内存中,因此具有内存地址。变量 health 包含一个整数值 32,它存储在位于 0x23fba4 的栈位置上,而变量 game 包含一个字符串,它存储在从 0x23fb90 开始的堆上(这些是我执行程序时的地址,当你运行程序时它们会不同)。

变量是值的绑定,是指向这些值的指针或引用。变量 game 是对 “Space Invaders” 的引用。值的地址由 & 运算符给出。所以,&health 指针是存储值 32 的地址,&game 指针是存储值 “Space Invaders” 的地址。

我们可以使用格式字符串 {:p} 来打印这些地址,像这样:

println!("health-value 的地址: {:p}", &health); 
// 打印 0x23fba4 
println!("game-value 的地址: {:p}", &game); // 打印 0x23fb90 
println!("game-value: {}", game); // 打印 "Space Invaders"  

现在,我们在内存中有以下情况(每次执行时内存地址将不同):

img

我们可以创建一个别名,这是另一个引用,它指向内存中的同一个位置,像这样:

let game2 = &game; 
println!("{:p}", game2); // 打印 0x23fb90  

为了获取被引用的值而不是引用 game2 本身,使用星号 * 操作符进行解引用,像这样:

println!("{}", *game2); // 打印 "Space Invaders"

println! 宏很聪明,所以 println!("{}", game2); 也会打印出相同的值,如下面的语句所做的那样:

println!("game: {}", &game); 

上述故事有点简化了,因为 Rust 会尽可能地在栈上分配大小不会改变的值,但它旨在帮助你更好地理解对一个值的引用意味着什么。

我们已经知道,let 绑定是不可变的,所以值不能被改变,如 health = 33;。

这会导致以下错误:

error: re-assignment of immutable variable `health` 

如果变量 y 被声明为 let y = &health;,那么引用 *y 就是值 32。引用变量也可以给定一个类型,如 let x: &i64;,这样的引用可以在代码中传递。在这个 let 绑定之后,x 实际上还没有真正指向一个值,它不包含一个内存地址。在 Rust 中,没有办法创建一个空指针,就像你在其他语言中可以做的那样,试图给 x 赋值为 nil 或 null 甚至单位值 () 都会导致错误。仅这一点就为 Rust 程序员节省了无数的错误。此外,试图在表达式中使用变量 x,例如语句:

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

这会导致以下错误:

error: use of possibly uninitialized variable: `x`

对不可变变量的可变引用(表示为 &mut 指针)是禁止的,否则不可变变量可以通过其可变引用被改变:

  let tricks = 10; 
  let reftricks = &mut tricks;  

这会导致以下错误:

cannot borrow immutable local variable `tricks` as mutable

对可变变量 score 的引用可以是不可变的或可变的,就像下面例子中的 score2 和 score3 变量一样:

  let mut score = 0; 
  let score2 = &score;  

但是你不能通过不可变引用 score2 改变 score 的值,因为这会导致错误,如下:

*score2 = 5;

这将导致错误:不能对不可变的借用内容 *score2 进行赋值
通过可变引用如 score3 才能改变变量 score 的值:

let mut score = 0; 
let score3 = &mut score; 
*score3 = 5;  

由于我们稍后会看到的原因,你只能对一个可变变量创建一个可变引用:

let score4 = &mut score; 

如果你这样做,会抛出如下错误:

error: cannot borrow `score` as mutable more than once at a time

在这里,我们接触到了 Rust 内存安全系统的核心,借用变量是其关键概念之一。我们将在[第7章]《确保内存安全和指针》中更详细地探讨这个问题。

堆是一个比栈大得多的内存部分,所以当内存位置不再需要时,尽快释放它们是很重要的。在 Rust 中,每个变量都有一定的生命周期,它说明了变量在程序内存中存在多久。Rust 编译器会看到变量的生命周期何时结束(换句话说,变量超出作用域),并在编译时插入代码,以在执行该代码时释放其内存。这种行为是 Rust 独有的,在其他常用语言中不会这样做。

栈上的值可以通过创建一个围绕它们的 Box 来装箱,即分配到堆上,就像下面 x 的值一样:

let x = Box::new(5i32); 

Box 对象引用堆上的一个值。我们也将在《确保内存安全和指针》的Boxes部分更仔细地看看它。

【一起学Rust 基础篇】Rust基础——变量和数据类型 Rust定义变量需要使用关键词let,这点和Javascript是一致的,如果你有JS开发的经验,那你应该很熟悉。现在我们定义几个变量letx=5;以上的几个变量都是没有问题的,定义了三个变量,x是整数型的,y是浮点型的,z是字符串型的。除此以外,Rust还支持指定变量类型来定义变量letxi32=5;letyf64=5.0;letstr其实我们并不是一定得指定类型,因为Rust可以自动推断你使用的是哪种类型。以上就是本期所要讲述的内容了。本期主要讲了变量的定义。... 阅读详情

相关推荐

(程序设计方法与实践)达拉崩吧的酒宴

达拉崩吧的酒宴 Description 很久很久以前,巨龙突然出现,带来灾难带走了公主又消失不见,王国十分危险,世间谁最勇敢,一位勇者赶来大声喊:“我要带上最好的剑,翻过最高的山,闯进最深的森林,把公主带回到面前”……最后,英雄 达拉崩巴斑得贝迪卜多比鲁翁 ,他战胜了巨龙 昆图库塔卡提考特苏瓦西拉松 ,国王把公主 米娅莫拉苏娜丹妮谢莉红 嫁给了 达拉崩巴斑得贝迪卜多比鲁翁 。 于是国王第二天要在 蒙达鲁克硫斯伯古比奇巴勒城 举办酒宴,一共准备了 N 桶酒。此时一位忠诚的仆人来报,有人在其中一桶酒里下毒,

What_If_I的博客 892

Rust 变量和基本类型

Rust 变量

mr1jie的博客 1194

使用ZYNQ芯片和LVGL框架实现用户高刷新UI设计系列教程(第七讲)

默认是第一种键盘模式,当需要切换模式,进入到ta_event_cb函数修改模式,下面代码以数字模式举例子lv_keyboard_set_mode(kb, LV_KEYBOARD_MODE_NUMBER);在该界面中可以设置键盘文字的大小和文本类型,最下方判断键盘是否支持中文输入(中文输入,当汉字库不够大时,用户点击中文输入会少很多字)。//当LV_USE_KEYBOARD为1时启用虚拟键盘,LV_USE_ZH_KEYBOARD为1时支持中文输入。随后在系统设置界面中点击项目选项,选择显示键盘。

weixin_38828382的博客 1414

Rust学习-变量和类型

比如对于一个byte(8 bits)的数据来说,如果存的是无符号数,那么它的表达范围是0~255,如果存的是有符号数,那么它的表达范围是-128~127.在整数的算数运算中,有一个比较头疼的事情是"溢出"。在此例中,编译器只知道x是一个整数,但是具体是i8 i16 i32或者u8 u16 u32等,并没有足够的信息判断,这些都是有可能的。也就是说,Rust设计者希望在发生类型转换的时候不是偷偷摸摸进行的,而是显式的标记出来,防止隐藏bug.虽然在很多时候会让代码显得不那么精简,但这也算是一种合理的折中。

L18395026811的博客 617

从实验室到晶圆厂:一文看懂二维半导体(如MoS2)的CVD生长与晶体管制造挑战

本文深入探讨了二维半导体(如MoS2)从实验室研究到晶圆厂量产的CVD生长与晶体管制造关键技术挑战。重点分析了晶圆级二维半导体的CVD生长工艺优化、晶体管制造的四大界面工程难题,以及掺杂与集成的产业化解决方案,为二维半导体在集成电路领域的应用提供技术参考。

weixin_42651748的博客 471

CentOS8静默安装Oracle11.2.0.1

背景 新安装oracle,用静默安装方式就不需要安装图形界面了,省时省力。 前期准备工作与图形化安装一样,如创建用户|用户组、环境变量、内核参数、创建目录等. 可参考图形化安装,链接:https://blog.youkuaiyun.com/heroicpoem/article/details/104229369 环境 平台 版本 操作系统 centOS 8 Oracle 11gR2 1.响应文件 响应文件的内容就是图形化安装时手工设置的选项内容。 解压后,database/response/db

heroicpoem的专栏 4518

【一起学Rust | 基础篇】Rust基础——变量和数据类型

变量是一个编程语言必要的内容,学习任何一门编程语言都离不开变量,而是基础中的基础,学习Rust也是这样的。本期我们将从Rust变量的概念开始讲起,同时搭配编程案例,辅以作业,帮助大家学习和理解Rust的变量基础概念。......

专注Rust编程与技术分享,涵盖C++、Python等开发实战,新手友好,专注实战,助力编程成长。 10万+

时钟门控ICG单元的timing问题

本文探讨了数字IC设计中门控时钟(ICG)的时序收敛问题,重点分析了ICG单元在setup时序检查中易出现违例的原因及优化方法。文章指出,由于ICG单元不在时钟树平衡范围内,其时钟路径延迟通常小于后续寄存器,导致setup时序难以满足。提出的解决方案包括:1)将ICG尽量靠近受控寄存器放置;2)使用set_clock_gating_check命令加强时序约束;3)在布局阶段设置负时钟延迟;4)CTS阶段设置插入延迟。同时强调set_clock_gating_check命令对ICG单元同样有效,并介绍了ICG

u011075954的专栏 1104

【Rust 基础篇】Rust 变量详解

在 Rust 中,我们使用let关键字来定义变量。let:关键字用于声明变量。:变量的名称,由字母、数字和下划线组成,以字母或下划线开头。type:变量的类型,在 Rust 中所有变量都必须明确指定类型。value:可选项,用于给变量赋初值。本篇博客介绍了 Rust 中的变量定义和使用。我们了解了变量的语法、可变性和作用域的概念,并通过示例代码演示了其用法。Rust 是一门强大而安全的编程语言,对变量的类型和可变性的严格控制可以帮助开发者避免一些常见的错误。

繁依Fanyi的博客 1465

快速了解Spyder

一 面板介绍菜单栏:放置所有功能工具栏:放置快捷菜单,可以通过菜单栏中的View的Toolbars的复选框来勾选工作区:写代码的地方属性页的标题栏:可以显示当前代码的名字和位置查看栏:查看文件、调试时的对象及变量输出栏:查看程序的输出信息,也可以作为shell终端来输入Python语句状态栏:用来显示当前文件权限、编码,光标指向位置和系统内存二 注释功能注释功能为编写代码很常用功能,下面介绍Spy...

实践求真知 1万+

百元DIY手机荧光计:低成本荧光检测平台搭建与实战

荧光检测是一种基于物质受特定波长光激发后发射更长波长荧光的分析技术,其核心原理在于光与物质的相互作用。通过选择性激发与检测,该技术能实现对痕量物质的高灵敏度、高特异性定量分析,在生物医学、环境监测和食品安全等领域具有重要价值。传统荧光分光光度计虽精度高,但成本昂贵、体积庞大且操作复杂,限制了其在现场快检和普及教育中的应用。本文聚焦于如何利用智能手机的高性能摄像头和处理器,结合低成本光学滤光片和LED光源,构建一个便携、经济的DIY荧光检测平台。该方案通过简化光路设计,采用带通滤光片进行波长选择,并利用图像处

weixin_34194829的博客 304

Rust编程学习(一): 变量与数据类型

常量是指绑定到一个标识符且不允许改变的值,一旦定义后就没有任何方法能改变其值了。常量名通常是大写字母,且必须指定常量的数据类型常量与不可变变量对比:1)常量声明使用const关键字,且必须注明值的类型。2)常量不能遮蔽,不能重复定义。3)常量可以在任何作用域中声明,包括全局作用域。4)常量只能被赋值为常量表达式或数学表达式,不能是函数返回值,或是其他在运行时才能确定的值。

weixin_46564301的博客 2281

ChatTutor:让AI老师“会写会画”,打造可视化、互动式智能教育新范式

ChatTutor是一款突破性的开源AI教学助手,通过可视化电子白板实现"边讲边写"的沉浸式教学体验。该项目支持数学公式手写输入、动态函数绘图、自动生成思维导图等功能,采用多智能体架构实现专业协同。未来将扩展至编程、物理等STEM教育领域,适用于学生自学、教师备课和教育平台集成。作为MIT协议开源项目,ChatTutor通过赋予AI"教学肢体语言",推动教育从信息传递转向可视化互动建构,重新定义了AI助教的可能性。

这里汇聚了前沿的技术分享与实用的开发技巧,带你探索从创意到企业的技术创业之路。 423

[初学rust] 02_rust 中的变量和数据类型

变量的类型是在编译期确定的,不能改变。类型之间不能进行运算,除非使用as关键字来强制转换。数据类型种类和C++差不多Rust的数据类型是有method的,可以直接调用。

u012989445的博客 1188

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【一起学Rust 基础篇】Rust基础——变量和数据类型_rust 变量指定数据类型(2)

Rust定义变量需要使用关键词,这点和Javascript是一致的,如果你有JS开发的经验,那你应该很熟悉。现在我们定义几个变量以上的几个变量都是没有问题的,定义了三个变量,x是整数型的,y是浮点型的,z是字符串型的。除此以外,Rust还支持指定变量类型来定义变量其实我们并不是一定得指定类型,因为Rust可以自动推断你使用的是哪种类型。

2401_84181108的博客 1062

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

RUST零基础入门——变量和数据类型

当我们尝试更改指定为不可变的值时,我们会遇到编译时错误,这一点很重要,因为这种情况可能会导致错误。如果我们的代码的一部分在假设值永远不会改变的情况下运行,而代码的另一部分更改了该值,则代码的第一部分可能不会执行其设计目的。事后很难追查这种错误的原因,尤其是当第二段代码有时只更改值时。Rust 编译器保证当你声明一个值不会改变时,它确实不会改变,所以你不必自己跟踪它。当然也不是完全不可变,RUST提供了两种可变的方式,一是通过。值得注意的是,RUST的变量是默认不可变的,什么意思呢?,声明常量的关键字是。

yao_tao11的博客 760

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

rust学习笔记-变量和类型

变量 通常一门的语言的变量是没有啥可以说道的,无法就是变量命名规则:以字母、下划线和数字组成,并且数字不能开头,没啥好说的。 但rust的变量奇怪的地方是, 变量不可变 譬如这样一个简单到不能再简单的代码 fn main() { let a =4; a = 3; println!("{}",a) } 编译的时候就会报错 3 | a = 3; | ^^^^^ cannot assign twice to immutable variable 不能二次分配不可变变

柳清风的专栏 1571

Rust教程-2.1 变量和数据类型

在 Rust 中,变量的声明和使用是编程的基础。本节将详细介绍如何声明变量、理解 Rust 的基本数据类型以及复合数据类型的使用。

wrn_csdn的博客 1798

rust类型和变量(二)

基础知识创建变量:let 关键字//变量默认是不可变的// 可变变量:变量名称前加 mut//常量:const 关键字// Shadowing: 隐藏。

gitxuzan 316

【一起学Rust 基础篇】Rust基础——变量和数据类型_rust 变量指定数据类型(1)

以上就是本期所要讲述的内容了。本期主要讲了变量的定义变量的可变性基本变量类型整型布尔型字符型复合型数组元组常量虽然很努力的组织内容了,但还是感觉不是很合理,在后期一定要调整,方便新手入门,让更多人能够学到Rust。作业完成以下作业是你学好rust的重要组成部分。以下题目摘自《Rust练习实践》

2401_84181108的博客 695

Rust学习笔记-常见的编程概念-变量和数据类型

当变量不可变时,一旦值被绑定一个名称上,你就不能改变这个值。在尝试改变预设为不可变的值时,产生编译时错误是很重要的,因为这种情况可能导致 bug。如果一部分代码假设一个值永远也不会改变,而另一部分代码改变了这个值,第一部分代码就有可能以不可预料的方式运行。不得不承认这种 bug 的起因难以跟踪,尤其是第二部分代码只是会改变值。Rust 编译器保证,如果声明一个值不会变,它就真的不会变,所以你不必自己跟踪它。这意味着你的代码更易于推导。尽管变量默认是不可变的,你仍然可以mut[常量。

快乐的小小程序猿 1223

rust实战系列四:变量和类型

因为在变量声明语句中,最重要的是 变量本身,而类型其实是个附属的额外描述,并非必不可少的部分。其中,赋值号左边的部分是一个“模式”,第一行代码是对tuple的模式解构,第 二行代码是对结构体的模式解构。所以,在Rust中,一般把声明的局部变量并初始 化的语句称为“变量绑定”,强调的是“绑定”的含义,与C/C++中的“赋值初始化”语 句有所区别。从语法分析的角度来说,Rust的变量声明语法比C/C++语言的简单,局部变量 声明一定是以关键字let开头,类型一定是跟在冒号:的后面。此时,变量x才是可读写的。

Mr_Roki的博客 554

【Rust深入浅出-2】变量和基本数据类型

Rust深入浅出教程第二章《变量和基本数据类型》本章节将带领你了解rust这门强类型语言中的变量和rust具有的基本数据类型本章简单介绍了rust中变量申明和基本的数据类型。在下一章,我们将学习rust中的运算符。下一章常见运算符。

Evanpatchouli 的博客 275
上一篇: 第 4 章:IR 代码生成的基础知识
下一篇: 第一章: 理解 LLVM
段舸
博客等级 码龄3年 533粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值