作者 | Florian GOTO

译者 | 弯月 责编 | 欧阳姝黎

出品 | CSDN(ID:CSDNnews)

以下为译文:

随着WebAssembly的进步,如果你想在JavaScript和Node.js的基础上,提高浏览器、服务器和边缘计算的性能,那么可以了解一下Rust。

Node.js技术栈与Rust的结合简直是天作之合,因为Rust能提供WebAssembly支持,而WebAssembly能在Node.js上运行。

本文将详细地介绍如何在Node.js上编译Rust,并运行WebAssembly。

注意:

对于以JavaScript为主的Node.js开发者来说,你可能不太熟悉类似于“std::wx::y”或“&xyz”之类的表述,但是没关系,我会详细解释。

与JavaScript和Node.js相比,Rust是一门较为低级的语言。这意味着,你需要熟悉计算机的工作原理,才能真正理解Rust。而Node.js更为高级,通常接触不到这些表述。

别忘了,Rust最初是一门非常接近底层硬件的系统编程语言。这样能获得更高的性能,但也会导致更高的复杂性。

Rust不会隐藏变量位于栈上还是堆上、以及因此导致的限制等细节。但它也提供了大量的库和模块(在Rust中称为crate),这一点很像Node.js,因此编程难度并不高。

创建一个Rust项目

本文所有的代码都可以利用Rust playground在线运行(当然,除了那些需要访问本地的代码之外)。

在安装好Rust之后,利用cargo命令(Rust的包管理器)创建一个新项目:

cargo new

这个命令将在当前目录下创建一个新文件夹。

或者你也可以将当前目录作为项目文件夹:

cargo init源代码位于src/目录下,入口为main.rs文件中的main函数(用fn关键字定义)。fn main() {println!("Hello, world!");

输出

Rust使用“宏”来输出到控制台。Rust中的宏用感叹号(!)表示。println!宏非常灵活:

fn main() {// string interpolationprintln!("Adding {} and {} gives {}", 22, 33, 22 + 33);// positional argumentsprintln!("Ypur name is {0}. Welcome to {1}. Nice to meet you {0}","Goto", "Rust"// named argumentsprintln!("{language} is very popular. It was created in {year}",language = "Rust",year = 2010// placeholder traits (using positional argument to avoid repeat)println!("{0}, in binary: {0:b}, in hexadecimal: {0:x}", 11);// debug trait (very useful to print anything)// if you try to print the array directly, you will get an error// because an array is not a string or number typeprintln!("{:?}", [11, 22, 33]);

运行代码查看输出:

cargo run

你将会看到下面的结果(以及一大堆编译信息——Rust是一门编译语言):

Adding 22 and 33 gives 55Ypur name is Goto. Welcome to Rust. Nice to meet you GotoRust is very popular. It was created in 2010Decimal: 11 Binary: 1011 Hexadecimal: b[11, 22, 33]

在Rust中,行尾必须使用分号(;),除非是函数最后一行的返回语句(稍后进一步解释)。

对数值输出进行高级格式化

fn main() {let x = 246.92385;let y = 24.69;let z = x / y;// print line macro with 3 decimal point precisionprintln!("z is {:.3}", z);// 9: total character space the number to occupy// (adds pre padding if necessary)println!("z is {:9.3}", z);// 0: placeholder number for padding charactersprintln!("z is {:09.3}", z);println!("z is {:09.3}\nx is {}", z, x);// print macro without new lineprint!("y is {:09.3}\n x is {}\n", y, x);// positional parametersprintln!("z is {0:05.1} and x is {1:.2}. \nx is also {1}", z, x)

输出结果:

z is 10.001z is 10.001z is 00010.001z is 00010.001x is 246.92385y is 00024.690x is 246.92385z is 010.0 and x is 246.92.x is also 246.92385

变量

fn main() {// variables are immutable by defaultlet pc = "Inspirion XYZ";println!("pc is {}", pc);// mutable variableslet mut age = 1;println!("age is {}", age);age = 2;println!("age is {}", age);// constants (must be uppercase and explicit type definition)const BRAND: &str = "Dell";println!("brand is {}", BRAND);// multiple assignment (tuple destructuring)// more on tuples later in the articlelet (status, code) = ("OK", 200);println!("status: {}, code: {}", status, code);

输出结果:

pc is Inspirion XYZage is 1age is 2brand is Dellstatus: OK, code: 200

基本类型

fn main() {// default integer numeric type is i32let num1 = 123;println!("{} - type: {}", num1, get_type(&num1));// default floating point numeric type is f64let num2 = 1.23;println!("{} - type: {}", num2, get_type(&num2));// explicit typinglet num3: i8 = 23;println!("{} - type: {}", num3, get_type(&num3));// max values// std is the standard library/crate,// it gives access to a rich variety of features,// here we use the type modules (i32, i16, etc.) and propertieslet max_i32 = std::i32::MAX;let max_i16 = std::i16::MAX;println!("max value for i32 is {}", max_i32);println!("max value for i16 is {}", max_i16);// booleanlet is_rust_fun: bool = true;println!("is_rust_fun is {} - type: {}",is_rust_fun,get_type(&is_rust_fun)let is_greater = 23 > 5;println!("is_greater is {} - type: {}",is_greater,get_type(&is_greater)// characters (unicode - up to 4 bytes length)let smiley = '';println!("smiley is {} - type: {}", smiley, get_type(&smiley));// helper function to print typesfn get_type(_: &T) -> &str {std::any::type_name::()

输出结果:

123 - type: i321.23 - type: f6423 - type: i8max value for i32 is 2147483647max value for i16 is 32767is_rust_fun is true - type: boolis_greater is true - type: boolsmiley is - type: char

浮点数

  • f32 (32位浮点数)

  • f64 (64位浮点数)


fn main() {// by default fractional values stored in f64
let my_float = 12.345677890123456789012345;println!("my_float is: {}", my_float);let a_float: f32 = 9.9438535983578493758;println!("a_float is: {}", a_float);let min_f32 = std::f32::MIN;println!("min_f32 is: {}\n", min_f32);let max_f32 = std::f32::MAX;println!("max_f32 is: {}\n", max_f32);let min_f64 = std::f64::MIN;println!("min_f64 is: {}\n", min_f64);let max_f64 = std::f64::MAX;println!("max_f64 is: {}\n", max_f64);

输出结果:

my_float is: 12.345677890123456a_float is: 9.943853min_f32 is: -340282350000000000000000000000000000000max_f32 is: 340282350000000000000000000000000000000min_f64 is: -179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000max_f64 is: 179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

位操作(高级内容,可以跳过)

Bitwise operations: on individual bits rather than sets of bytes.- binary representation, a sequence of bytes- underscore separator allowed for legibility- by default binary representations are store as i32fn main() {// stored as u8 by adding suffix u8
let mut value = 0b1111_0101u8;// will print base 10 (decimal) representation
println!("value is {}", value);:08b0 -> display leading zeros8 -> number of bits to displayb -> display binary representationprintln!("value is {:08b}", value);// bitwise NOT: invert individual bits
value = !value; // 0000_1010println!("value is {:08b}", value);// bitwise AND: used to clear the value of a specific bitvalue = value & 0b1111_0111; // -> 0000_0010println!("value is {:08b}", value);// bitwise AND: used to check value of a specific bit// if a specific bit is 0 or 1, useful to check status of registers for process state
println!("value is {:08b}", value & 0b0100_0000);// -> 0000_0000// bitwise OR: if either operand is 1, result is 1// useful to set value of a specific bit
value = value | 0b0100_0000; // -> 0100_0010println!("value is {:08b}", value);// bitwise XOR (exclusive OR):// result is 1 only when bits are different, otherwise 0// useful to set if bits are different
value = value ^ 0b0101_0101; // -> 0001_0111println!("value is {:08b}", value);// Bit Shift operators// shift bit pattern left or right by a number of bits// and backfill shifted bit spaces with zeros// shift left by 4 bits
value = value << 4; // -> 0111_0000println!("value is {:08b}", value);// shift right by 3 bits
value = value >> 3; // -> 0000_1110println!("value is {:08b}", value);

输出结果:

value is 245value is 11110101value is 00001010value is 00000010value is 00000000value is 01000010value is 00010111value is 01110000value is 00001110

布尔和二进制代数

fn main() {let a = true;let b = false;println!("a is {}\nb is {}", a, b);println!("NOT a is {}", !a);println!("a AND b is {}", a & b);println!("a OR b is {}", a | b);println!("a XOR b is {}", a ^ b);// boolean casted to integer begets 0 or 1println!("a XOR b is {}", (a ^ b) as i32); // 1let c = (a ^ b) | (a & b);println!("c is {}", c);// short-circuiting logical operations:// right operand not evaluatedlet d = true || (a & b);println!("d is {}", d);// the panic macro is not evaluated,// so the process ends with status 0 (OK, no error)// panics exit the program immediately (like throwing error in Node.js)let e = false && panic!();println!("e is {}", e);

输出结果:

a is trueb is falseNOT a is falsea AND b is falsea OR b is truea XOR b is truea XOR b is 1c is trued is truee is false

算术操作

fn main() {// can only do arithmetic operations on same type operandslet a = 11;let b = 33;let c = a + b;println!("c is {}", c);let d = c - b;println!("d is {}", d);let e = a * d;println!("e is {}", e);// type casting (careful with precision loss and type compatibility)let f = c as f32 / 4.5;println!("f is {}", f);// operator precedence control
let g = 43.5432 % (a as f64 * e as f64);println!("g is {}", g);

输出结果:

c is 44d is 11e is 121f is 9.777778g is 43.5432

比较操作

can only compare values of same typefn main() {let a = 11;let b = 88;println!("a is {}\nb is {}", a, b);println!("a EQUAL TO b is {}", a == b);println!("a NOT EQUAL TO b is {}", a != b);println!("a GREATER THAN b is {}", a > b);println!("a GREATER THAN OR EQUAL TO b is {}", a >= b);println!("a LESS THAN b is {}", a < b);println!("a LESS THAN OR EQUAL TO b is {}", a <= b);let c = true;let d = false;println!("\nc is {}\nd is {}", c, d);println!("c EQUAL TO d is {}", c == d);println!("c NOT EQUAL TO d is {}", c != d);println!("c GREATER THAN d is {}", c > d);println!("c GREATER THAN OR EQUAL TO d is {}", c >= d);println!("c LESS THAN d is {}", c < d);println!("c LESS THAN OR EQUAL TO d is {}", c <= d);

输出结果:

a is 11b is 88a EQUAL TO b is falsea NOT EQUAL TO b is truea GREATER THAN b is falsea GREATER THAN OR EQUAL TO b is falsea LESS THAN b is truea LESS THAN OR EQUAL TO b is truec is trued is falsec EQUAL TO d is falsec NOT EQUAL TO d is truec GREATER THAN d is truec GREATER THAN OR EQUAL TO d is truec LESS THAN d is falsec LESS THAN OR EQUAL TO d is false

字符

fn main() {// Unicode scalar value stored using 4 bytes (32 bits)// contrary to C like languages that store it in 1 bytelet letter: char = 'z';let number_char = '9';let finger = '\u{261D}';println!("letter is {}", letter);println!("number_char is {}", number_char);println!("finger is {}", finger);

输出结果:

letter is znumber_char is 9finger is ☝

计算平均值

fn main() {let a = 33;let b = 4.9;let c: f32 = 123.5;let average = (a as f32 + b as f32 + c) / 3.0;println!("average is {}", average);assert_eq!(average, 53.8);println!("test passed.");

输出结果:

average is 53.8test passed.

数组

fn main() {// fixed length and single typed// stored in contiguous memory locationslet letters = ['a', 'b', 'c']; // type: [char; 3]let first_letter = letters[0];println!("first_letter is {}", first_letter);// to modify elements in array, it must be mutablelet mut numbers = [11, 22, 44]; // type is [i32; 3]numbers[2] = 33;println!("numbers is {}", numbers[2]);// empty array declaration (memory allocated)let words: [&str; 2];words = ["ok"; 2]; // repeat expression, equivalent to ["ok", "ok"]println!("words is {:?}", words);length of usize is based on number of bytes needed to reference memory in your target architecture:- for 32 bit compilation target -> usize is 4 bytes- for 64 bit compilation target -> usize is 8 byteslet ints = [22; 5];let length: usize = ints.len();println!("length is {}", length);// get size in memory (mem module of the std crate)let mem_size_byte = std::mem::size_of_val(&ints);println!("mem_size_byte is {}", mem_size_byte);// get slice from arraylet mut slice: &[i32] = &ints;println!("slice is {:?}", slice);
slice = &ints[3..5];println!("slice is {:?}", slice);

输出结果:

first_letter is anumbers is 33words is ["ok", "ok"]length is 5mem_size_byte is 20slice is [22, 22, 22, 22, 22]slice is [22, 22]

多维数组

fn main() {let d2: [[i32; 3]; 3] = [[9, 8, 7], [6, 5, 4], [3, 2, 1]];let value = d2[1][0];println!("value is {}", value);// mutating a tuplelet d3: [[[&str; 100]; 20]; 5];d3 = [[["ok"; 100]; 20]; 5];println!("value d3[3][11][35] is {}", d3[3][11][35])

输出结果:

value is 6value d3[3][11][35] is ok

向量

fn main() {// vectors = mutable size arrayslet mut letters: Vec = vec!['a', 'b', 'c'];println!("letters are {:?}", letters);let first_letter = letters[0];println!("first_letter is {}", first_letter);// add value to vectorletters.push('d');letters.push('e');letters.push('f');println!("letters are {:?}", letters);// remove last valueletters.pop();println!("letters are {:?}", letters);let mut numbers: Vec = vec![11, 22, 44];numbers[2] = 33;println!("numbers is {}", numbers[2]);let words: Vec<&str>;words = vec!["ok"; 2];println!("words are {:?}", words);let mut ints = vec![22, 33, 44, 55, 66, 77];let length: usize = ints.len();println!("length is {}", length);let mem_size_byte = std::mem::size_of_val(&ints);println!("mem_size_byte is {}", mem_size_byte);// slice from vectorlet mut slice: &[i32] = &ints;println!("slice is {:?}", slice);slice = &ints[2..5];println!("slice is {:?}", slice);// iterate over vectorfor it in ints.iter() {println!("it is {}", it);// mutate vector items while iteratingfor it in ints.iter_mut() {// dereference the pointer to get and set value (*it)*it *= *it;println!("ints is {:?}", ints);

输出结果:

letters are ['a', 'b', 'c']first_letter is aletters are ['a', 'b', 'c', 'd', 'e', 'f']letters are ['a', 'b', 'c', 'd', 'e']numbers is 33words is ["ok", "ok"]length is 6mem_size_byte is 24slice is [22, 33, 44, 55, 66, 77]slice is [44, 55, 66]it is 22it is 33it is 44it is 55it is 66it is 77ints is [484, 1089, 1936, 3025, 4356, 5929]

元组

fn main() {// can have max 12 mixed type values// adding more values and it will no longer be a tuple typelet a_tuple: (&str, u8, char) = ("ok", 0, 'd');let first_item = a_tuple.0;println!("first_item is {}", first_item);// mutate a tuplelet mut b_tuple = ("ok", 0);b_tuple.0 = "ko";b_tuple.1 += 1;println!("b_tuple.1 is {}", b_tuple.1);// destructure a tuplelet c_tuple = ("en", "US", 1);let (language, country, code) = c_tuple;println!("language is: {}\ncountry is: {}\ncode is: {}",language, country, code

输出结果:

first_item is okb_tuple.1 is 1language is: encountry is: UScode is: 1

函数

fn main() {be_polite();// inferred types for y and z are the ones used as parameters of add()// to be clear, if you do not declare a specific type for variables, these variables will assume the type of the arguments of the function where first used// remember, by the default inferred type is i32 for integerslet y = 12;let z = 34;// now y and z are considered u8 type because this is how they are first used as function argumentsadd(y, z);// passing later y and z to another fn with different param types will panic// guess_number(z) // -> expects a i32 not a u8// need for explicit cast:guess_number(y as i32)fn be_polite() {println!("Greetings, pleased to meet you.");guess_number(25)fn guess_number(number: i32) {println!("Indeed, {} is the correct answer", number)fn add(a: u8, b: u8) {let sum = a + b;println!("sum is {}", sum)

输出结果:

Greetings, pleased to meet you.Indeed, 25 is the correct answersum is 46Indeed, 12 is the correct answer

语句和表达式

fn main() {// Statement performs an action without returning a value// statements end with a semicolon: a = 6;// an expression evaluates to a resulting value// expressions do NOT end with a semicolon: 3 + 4 which evaluates to 7// adding a semicolon to an expressions transforms it into an statement// expressions are used as parts of statements: let total = r + c;\n\t{}\n\t{}",// where "r + c" is an expression and "let total = r + c;" is a statementprintln!("expression 4 + 5 evaluates to: {}", 4 + 5);

输出结果:

expression 4 + 5 evaluates to: 9

函数返回类型

fn main() {let result = square(3);println!("result is {}", result);let result_tuple = triple(33);let (input, result1) = result_tuple;println!("result_tuple is {:?}", result_tuple);// {:?} ==> debug formattingprintln!("input {} evaluates to {}", input, result1);let nothing: () = does_not_return();println!("nothing (union data type) is {:?}", nothing)fn square(number: i32) -> i32 {println!("processing square({})", number);// expression returning a valuenumber * number// " return number * number;" is also valid syntax// multiple returns with tuplesfn triple(number: i32) -> (i32, i32) {println!("tripling the number: {}", number);let input = number;let result = number * 3;(input, result)// union data type// used when no meaningful values returned by a fn// represented by empty ()// it is optionalfn does_not_return() -> () {println!("ain't returning nuthing!")

输出结果:

processing square(3)result is 9tripling the number: 33result_tuple is (33, 99)input 33 evaluates to 99ain't returning nuthing!nothing (union data type) is ()

闭包

fn main() {// closures are anonymous functions that have access to variables in the enclosing scope// long formlet double = |n1: u8| -> u8 { n1 * 2 };// short formlet triple = |n1| n1 * 3;const DAYS_IN_YEAR: u16 = 365;// referencing variable from enclosing scopelet quadruple_than_add_number_days_in_year = |n1: i32| n1 * 4 + (DAYS_IN_YEAR as i32);const FACTOR: i32 = 22;let multiple_by_22 = |x| FACTOR * x;println!("{}", double(11));println!("{}", triple(99));println!("{}", quadruple_than_add_number_days_in_year(44));println!("{}", multiple_by_22(5));

输出结果:

22297541110

摄氏度到华氏度转换

fn main() {let (celsius, farenheit) = to_farenheit(40.0);println!("{} celsius is {} farenheit", celsius, farenheit);assert_eq!(farenheit, 104.0);// will not execute if assertion failsprintln!("test passed");fn to_farenheit(celsius: f32) -> (f32, f32) {let farenheit = (1.8 * celsius) + 32.0;// return statement (no semicolon)(celsius, farenheit)

条件执行

fn main() {let x = 5;if x == 5 {println!("x is 5");// if expressions (equivalent of ternary operator in JS/Node.js)let x_odd = if x % 2 == 0 { "odd" } else { "even" };println!("x_odd is {}", x_odd);

输出结果:

x is 5x_odd is even

多重条件(if/else if)

fn main() {let x = 2;let y = 5;if x > y {println!("x is greater than y");} else if x < y {println!("x is less than y");} else {println!("x is equal to y");

输出结果:

x is less than y

循环赋值

fn main() {let mut count = 0;// infinite looploop {if count == 10 {break;count += 1;println!("count is {}", count);println!("\nAfter first loop.\n");// returning a value from loop expressionlet result = loop {if count == 15 {// returning a value with break statementbreak count * 20;count += 1;println!("count is {}", count);println!("\nAfter second loop, result is {}", result);

输出结果:

count is 1count is 2count is 3count is 4count is 5count is 6count is 7count is 8count is 9count is 10After first loop.count is 11count is 12count is 13count is 14count is 15After second loop, result is 300

while循环

fn main() {let mut count = 0;let letters: [char; 5] = ['a', 'b', 'c', 'd', 'e'];while count < letters.len() {println!("letter[{}] is {}", count, letters[count]);count += 1;// contrary to loop expressions, the break statement in while loop cannot return a value

输出结果:

letter[0] is aletter[1] is bletter[2] is cletter[3] is dletter[4] is e

for循环

fn main() {let message = ['m', 'e', 's', 's', 'a', 'g', 'e'];/* Iterator- implements logic to iterate over each item in a collection- next() method returns the next item in a sequencefor item in message.iter() {println!("current item is {}", item);println!("");// to also get the indexes when iterating// enumerate() returns a tuple with index/item_reference pair// to get the item use &item// because the iterator gives back a reference (&)// if you don't use the &, you get the reference not the value// adding the & allows you to borrow the variable without taking ownership (more on that later) - then when you use the variable in the for loop scope, you access the valuefor (index, &item) in message.iter().enumerate() {println!("item {} is {}", index, item);if item == 'e' {break;println!("");// iterating over a range of numbers// excludes the end value of the rangefor number in 0..5 {println!("number is {}", number);

输出结果:

current item is mcurrent item is ecurrent item is scurrent item is scurrent item is acurrent item is gcurrent item is eitem 0 is mitem 1 is enumber is 0number is 1number is 2number is 3number is 4

嵌套循环

fn main() {let mut matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];// reading from matrixfor row in matrix.iter() {for number in row.iter() {print!("{}\t", number);println!("");println!("=======================");// modifying values from mutable matrix// iter_mut() returns mutable referencesfor row in matrix.iter_mut() {for number in row.iter_mut() {// dereference with asterisk to get the value itself*number += 20;print!("{}\t", number);println!("");

输出结果:

1 2 34 5 67 8 921 22 2324 25 2627 28 29

猜数游戏

use rand::Rng;use std::io;fn main() {println!("Guess a number");println!("Please enter your guess:");let secret_number = rand::thread_rng().gen_range(1, 101);println!("The secret number is {}", secret_number);// "::" is used for associated functions of a given type (equiv to static methods in OOP)// String::new() creates an empty string of type String (growable UTF-8 encoded text)let mut guess = String::new();std::io::stdin, if you don't use the import at the top of filestd::io::stdin() returns an instance of a std::io::Stdin typeio::stdin().read_line(&mut guess).expect("Failed to read line");println!("You guess: {}", guess);

统计基础

fn main() {let numbers = [1, 9, -2, 0, 23, 20, -7, 13, 37, 20, 56, -18, 20, 3];let mut max: i32 = numbers[0];let mut min: i32 = numbers[0];let mut mean: f64 = 0.0;for item in numbers.iter() {mean += *item as f64;if *item > max {max = *item;if *item < min {min = *item;mean /= numbers.len() as f64;assert_eq!(max, 56);assert_eq!(min, -18);assert_eq!(mean, 12.5);println!("Test passed!");

输出结果:

Test passed!

作用域

fn main() {let planet = "Dunya";if true {let planet = "Jupiter";println!("planet is {}", planet);println!("planet is {}", planet);

输出结果:

planet is Jupiterplanet is Dunya

变量可变性

fn main() {let car = "Mitsubishi";println!("car is a {}", car);// code block, has its own scope// varable shadowinglet car = 1;println!("car is a {}", car);println!("car is a {}", car);

输出结果:

car is a Mitsubishicar is a 1car is a Mitsubishi

栈和堆

fn main() {println!("=== STACK ====\n");println!("- values stored in sequential order of insertion");println!("- data added in LIFO (last in first out)");println!("- stores variables - pushing values on the stack");println!("- also holds info for function execution");println!("- stack have very fast access because no guessing where to put data, it will be on top"println!("- stacks are limited in size");println!("- all data in stack must have a known fixed size\n");func1();println!("func1 done");println!("pop variable y off the stack");println!("pop variable z off the stack\n");println!("\n\n=== HEAP ====\n");println!("- adding data to heap, search for large enough place in memory to store data");println!("- marks memory spot as being used (allocating) and put data in it");println!("- accessing data in heap is more complex than the stack because the stack allocates anywhere in available memory");println!("- slower than stack");println!("- dynamically add and remove data");println!("\n\n=== POINTER ====\n");println!("- data type that stores a memory address");println!("- pointers have a fixed size so can be stored on the stack");println!("- adding and accessing data on the heap is done through pointers (addresses in memory)");fn func1() {println!("func1 executing...");let y = 3.11;println!("push variable y = {} onto the stack", y);let z = 5;println!("push variable z = {} onto the stack", z);func2();println!("func2 done");println!("pop variable arr off the stack");fn func2() {println!("func2 executing...");let arr = [2, 3, 4];println!("push variable arr = {:?} onto the stack", arr);

输出结果:

=== STACK ====- values stored in sequential order of insertion- data added in LIFO (last in first out)- stores variables - pushing values on the stack- also holds info for function execution- stack have very fast access because no guessing where to put data, it will be on top- stacks are limited in size- all data in stack must have a known fixed sizefunc1 executing...push variable y = 3.11 onto the stackpush variable z = 5 onto the stackfunc2 executing...push variable arr = [2, 3, 4] onto the stackfunc2 donepop variable arr off the stackfunc1 donepop variable y off the stackpop variable z off the stack=== HEAP ====- adding data to heap, search for large enough place in memory to store data- marks memory spot as being used (allocating) and put data in it- accessing data in heap is more complex than the stack because the stack allocates anywhere in available memory- slower than stack- dynamically add and remove data=== POINTER ====- data type that stores a memory address- pointers have a fixed size so can be stored on the stack- adding and accessing data on the heap is done through pointers (addresses in memory)

字符串

Rust有两种字符串类型。

fn main() {// Two types of string representation:
// - string literals: hard coded into the executable.// these are immutable and must be known before compilation
// - String type: allocated data on the heap, \n\tmutable and dynamically generated at runtime// string literal stored on heap// String::from() creates a String type from a string literal// the sequence [m,a,r,s] will get stored on the heap// to access the string stored on heap, program holds a pointer to it on the stack (message variable)// that pointer on the stack includes first char memory address, length of string and the capacity so you know how much memory s allocated for it on the heaplet mut message = String::from("Jupiter");println!("message is {}", message);// append string to original// if more memory need than capacity, pointer address updated as well as length and capacity to reflect new location in memorymessage.push_str(" is smoke and mirrors");println!("message is {}", message);// pushing a charmessage.push('!');println!("message is {}", message);// get lengthprintln!("message lenght is {}", message.len());// get capacity in bytesprintln!("message capacity is {}", message.capacity());// check if emptyprintln!("Is empty: {}", message.is_empty());// substring searchprintln!("Contains smoke: {}", message.contains("smoke"));// replace substringprintln!("message is {}", message.replace("smoke","gaz"));// loop over words in string (split by white space)for word in message.split_whitespace() {println!("word is {}", word);// create string with capacitylet mut s = String::with_capacity(4); // 4 bytes capacityprintln!("s capacity is {} bytes", s.capacity());// 1 byte consumed// Latin alphabet letters usually have 1 byte size// remember Unicode supports 4-byte characterss.push('Q');s.push('W'); // 1 byte consumeds.push_str("er"); // 2 bytes consumed// exceeding string capacity (automagically increased and reallocation in memory)s.push('T'); // 1 byte consumedprintln!("s capacity is now {} bytes", s.capacity());

输出结果:

message is Jupitermessage is Jupiter is smoke and mirrorsmessage is Jupiter is smoke and mirrors!message lenght is 29message capacity is 56Is empty: falseContains smoke: truemessage is Jupiter is gaz and mirrors!word is Jupiterword is isword is smokeword is andword is mirrors!s capacity is 4 bytess capacity is now 8 bytes

所有权