作者 | 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 interpolation
println!("Adding {} and {} gives {}", 22, 33, 22 + 33);
// positional arguments
println!(
"Ypur name is {0}. Welcome to {1}. Nice to meet you {0}",
"Goto", "Rust"
// named arguments
println!(
"{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 type
println!("{:?}", [11, 22, 33]);
运行代码查看输出:
cargo run
你将会看到下面的结果(以及一大堆编译信息——Rust是一门编译语言):
Adding 22 and 33 gives 55
Ypur name is Goto. Welcome to Rust. Nice to meet you Goto
Rust is very popular. It was created in 2010
Decimal: 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 precision
println!("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 characters
println!("z is {:09.3}", z);
println!("z is {:09.3}\nx is {}", z, x);
// print macro without new line
print!("y is {:09.3}\n x is {}\n", y, x);
// positional parameters
println!("z is {0:05.1} and x is {1:.2}. \nx is also {1}", z, x)
输出结果:
z is 10.001
z is 10.001
z is 00010.001
z is 00010.001
x is 246.92385
y is 00024.690
x is 246.92385
z is 010.0 and x is 246.92.
x is also 246.92385
变量
fn main() {
// variables are immutable by default
let pc = "Inspirion XYZ";
println!("pc is {}", pc);
// mutable variables
let 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 article
let (status, code) = ("OK", 200);
println!("status: {}, code: {}", status, code);
输出结果:
pc is Inspirion XYZ
age is 1
age is 2
brand is Dell
status: OK, code: 200
基本类型
fn main() {
// default integer numeric type is i32
let num1 = 123;
println!("{} - type: {}", num1, get_type(&num1));
// default floating point numeric type is f64
let num2 = 1.23;
println!("{} - type: {}", num2, get_type(&num2));
// explicit typing
let 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 properties
let 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);
// boolean
let 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 types
fn get_type(_: &T) -> &str {
std::any::type_name::()
输出结果:
123 - type: i32
1.23 - type: f64
23 - type: i8
max value for i32 is 2147483647
max value for i16 is 32767
is_rust_fun is true - type: bool
is_greater is true - type: bool
smiley 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.345677890123456
a_float is: 9.943853
min_f32 is: -340282350000000000000000000000000000000
max_f32 is: 340282350000000000000000000000000000000
min_f64 is: -179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
max_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 i32
fn main() {
// stored as u8 by adding suffix u8
let mut value = 0b1111_0101u8;
// will print base 10 (decimal) representation
println!("value is {}", value);
:08b
0 -> display leading zeros
8 -> number of bits to display
b -> display binary representation
println!("value is {:08b}", value);
// bitwise NOT: invert individual bits
value = !value; // 0000_1010
println!("value is {:08b}", value);
// bitwise AND: used to clear the value of a specific bit
value = value & 0b1111_0111; // -> 0000_0010
println!("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_0010
println!("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_0111
println!("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_0000
println!("value is {:08b}", value);
// shift right by 3 bits
value = value >> 3; // -> 0000_1110
println!("value is {:08b}", value);
输出结果:
value is 245
value is 11110101
value is 00001010
value is 00000010
value is 00000000
value is 01000010
value is 00010111
value is 01110000
value 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 1
println!("a XOR b is {}", (a ^ b) as i32); // 1
let c = (a ^ b) | (a & b);
println!("c is {}", c);
// short-circuiting logical operations:
// right operand not evaluated
let 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 true
b is false
NOT a is false
a AND b is false
a OR b is true
a XOR b is true
a XOR b is 1
c is true
d is true
e is false
算术操作
fn main() {
// can only do arithmetic operations on same type operands
let 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 44
d is 11
e is 121
f is 9.777778
g is 43.5432
比较操作
can only compare values of same type
fn 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 11
b is 88
a EQUAL TO b is false
a NOT EQUAL TO b is true
a GREATER THAN b is false
a GREATER THAN OR EQUAL TO b is false
a LESS THAN b is true
a LESS THAN OR EQUAL TO b is true
c is true
d is false
c EQUAL TO d is false
c NOT EQUAL TO d is true
c GREATER THAN d is true
c GREATER THAN OR EQUAL TO d is true
c LESS THAN d is false
c 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 byte
let 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 z
number_char is 9
finger 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.8
test passed.
数组
fn main() {
// fixed length and single typed
// stored in contiguous memory locations
let 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 mutable
let 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 bytes
let 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 array
let mut slice: &[i32] = &ints;
println!("slice is {:?}", slice);
slice = &ints[3..5];
println!("slice is {:?}", slice);
输出结果:
first_letter is a
numbers is 33
words is ["ok", "ok"]
length is 5
mem_size_byte is 20
slice 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 tuple
let d3: [[[&str; 100]; 20]; 5];
d3 = [[["ok"; 100]; 20]; 5];
println!("value d3[3][11][35] is {}", d3[3][11][35])
输出结果:
value is 6
value d3[3][11][35] is ok
向量
fn main() {
// vectors = mutable size arrays
let 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 vector
letters.push('d');
letters.push('e');
letters.push('f');
println!("letters are {:?}", letters);
// remove last value
letters.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 vector
let mut slice: &[i32] = &ints;
println!("slice is {:?}", slice);
slice = &ints[2..5];
println!("slice is {:?}", slice);
// iterate over vector
for it in ints.iter() {
println!("it is {}", it);
// mutate vector items while iterating
for 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 a
letters are ['a', 'b', 'c', 'd', 'e', 'f']
letters are ['a', 'b', 'c', 'd', 'e']
numbers is 33
words is ["ok", "ok"]
length is 6
mem_size_byte is 24
slice is [22, 33, 44, 55, 66, 77]
slice is [44, 55, 66]
it is 22
it is 33
it is 44
it is 55
it is 66
it is 77
ints 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 type
let a_tuple: (&str, u8, char) = ("ok", 0, 'd');
let first_item = a_tuple.0;
println!("first_item is {}", first_item);
// mutate a tuple
let mut b_tuple = ("ok", 0);
b_tuple.0 = "ko";
b_tuple.1 += 1;
println!("b_tuple.1 is {}", b_tuple.1);
// destructure a tuple
let c_tuple = ("en", "US", 1);
let (language, country, code) = c_tuple;
println!(
"language is: {}\ncountry is: {}\ncode is: {}",
language, country, code
输出结果:
first_item is ok
b_tuple.1 is 1
language is: en
country is: US
code 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 integers
let y = 12;
let z = 34;
// now y and z are considered u8 type because this is how they are first used as function arguments
add(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 answer
sum is 46
Indeed, 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 statement
println!("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 formatting
println!("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 value
number * number
// " return number * number;" is also valid syntax
// multiple returns with tuples
fn 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 optional
fn does_not_return() -> () {
println!("ain't returning nuthing!")
输出结果:
processing square(3)
result is 9
tripling the number: 33
result_tuple is (33, 99)
input 33 evaluates to 99
ain't returning nuthing!
nothing (union data type) is ()
闭包
fn main() {
// closures are anonymous functions that have access to variables in the enclosing scope
// long form
let double = |n1: u8| -> u8 { n1 * 2 };
// short form
let triple = |n1| n1 * 3;
const DAYS_IN_YEAR: u16 = 365;
// referencing variable from enclosing scope
let 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));
输出结果:
22
297
541
110
摄氏度到华氏度转换
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 fails
println!("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 5
x_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 loop
loop {
if count == 10 {
break;
count += 1;
println!("count is {}", count);
println!("\nAfter first loop.\n");
// returning a value from loop expression
let result = loop {
if count == 15 {
// returning a value with break statement
break count * 20;
count += 1;
println!("count is {}", count);
println!("\nAfter second loop, result is {}", result);
输出结果:
count is 1
count is 2
count is 3
count is 4
count is 5
count is 6
count is 7
count is 8
count is 9
count is 10
After first loop.
count is 11
count is 12
count is 13
count is 14
count is 15
After 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 a
letter[1] is b
letter[2] is c
letter[3] is d
letter[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 sequence
for 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 value
for (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 range
for number in 0..5 {
println!("number is {}", number);
输出结果:
current item is m
current item is e
current item is s
current item is s
current item is a
current item is g
current item is e
item 0 is m
item 1 is e
number is 0
number is 1
number is 2
number is 3
number is 4
嵌套循环
fn main() {
let mut matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
// reading from matrix
for row in matrix.iter() {
for number in row.iter() {
print!("{}\t", number);
println!("");
println!("=======================");
// modifying values from mutable matrix
// iter_mut() returns mutable references
for 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 3
4 5 6
7 8 9
21 22 23
24 25 26
27 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 file
std::io::stdin() returns an instance of a std::io::Stdin type
io::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 Jupiter
planet is Dunya
变量可变性
fn main() {
let car = "Mitsubishi";
println!("car is a {}", car);
// code block, has its own scope
// varable shadowing
let car = 1;
println!("car is a {}", car);
println!("car is a {}", car);
输出结果:
car is a Mitsubishi
car is a 1
car 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 size
func1 executing...
push variable y = 3.11 onto the stack
push variable z = 5 onto the stack
func2 executing...
push variable arr = [2, 3, 4] onto the stack
func2 done
pop variable arr off the stack
func1 done
pop variable y off the stack
pop 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 heap
let 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 memory
message.push_str(" is smoke and mirrors");
println!("message is {}", message);
// pushing a char
message.push('!');
println!("message is {}", message);
// get length
println!("message lenght is {}", message.len());
// get capacity in bytes
println!("message capacity is {}", message.capacity());
// check if empty
println!("Is empty: {}", message.is_empty());
// substring search
println!("Contains smoke: {}", message.contains("smoke"));
// replace substring
println!("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 capacity
let mut s = String::with_capacity(4); // 4 bytes capacity
println!("s capacity is {} bytes", s.capacity());
// 1 byte consumed
// Latin alphabet letters usually have 1 byte size
// remember Unicode supports 4-byte characters
s.push('Q');
s.push('W'); // 1 byte consumed
s.push_str("er"); // 2 bytes consumed
// exceeding string capacity (automagically increased and reallocation in memory)
s.push('T'); // 1 byte consumed
println!("s capacity is now {} bytes", s.capacity());
输出结果:
message is Jupiter
message is Jupiter is smoke and mirrors
message is Jupiter is smoke and mirrors!
message lenght is 29
message capacity is 56
Is empty: false
Contains smoke: true
message is Jupiter is gaz and mirrors!
word is Jupiter
word is is
word is smoke
word is and
word is mirrors!
s capacity is 4 bytes
s capacity is now 8 bytes
所有权
热门跟贴