前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Node.js 开发者的 Rust 入门指南

Node.js 开发者的 Rust 入门指南

作者头像
五月君
发布2021-07-15 13:13:27
1.7K0
发布2021-07-15 13:13:27
举报
文章被收录于专栏:Nodejs技术栈Nodejs技术栈

以下为译文:

随着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的包管理器)创建一个新项目:

代码语言:javascript
复制
cargo new <PROJECT_NAME>

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

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

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

输出

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

代码语言:javascript
复制
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]);
}

运行代码查看输出:

代码语言:javascript
复制
cargo run

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

代码语言:javascript
复制
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中,行尾必须使用分号(;),除非是函数最后一行的返回语句(稍后进一步解释)。

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

代码语言:javascript
复制
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)
}

输出结果:

代码语言:javascript
复制
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

变量

代码语言:javascript
复制
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);
}

输出结果:

代码语言:javascript
复制
pc is Inspirion XYZ
age is 1
age is 2
brand is Dell
status: OK, code: 200

基本类型

代码语言:javascript
复制
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>(_: &T) -> &str {
std::any::type_name::<T>()
}

输出结果:

代码语言:javascript
复制
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位浮点数)
代码语言:javascript
复制
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);
}

输出结果:

代码语言:javascript
复制
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

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

代码语言:javascript
复制
/*
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);

输出结果:

代码语言:javascript
复制
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

布尔和二进制代数

代码语言:javascript
复制
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);
}

输出结果:

代码语言:javascript
复制
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

算术操作

代码语言:javascript
复制
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);
}

输出结果:

代码语言:javascript
复制
c is 44
d is 11
e is 121
f is 9.777778
g is 43.5432

比较操作

代码语言:javascript
复制
/*
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);
}

输出结果:

代码语言:javascript
复制
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

字符

代码语言:javascript
复制
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);
}

输出结果:

代码语言:javascript
复制
letter is z
number_char is 9
finger is ☝

计算平均值

代码语言:javascript
复制
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.");
}

输出结果:

代码语言:javascript
复制
average is 53.8
test passed.

数组

代码语言:javascript
复制
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);
}

输出结果:

代码语言:javascript
复制
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]

多维数组

代码语言:javascript
复制
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])
}

输出结果:

代码语言:javascript
复制
value is 6
value d3[3][11][35] is ok

向量

代码语言:javascript
复制
fn main() {
// vectors = mutable size arrays
let mut letters: Vec<char> = 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<i32> = 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);
}

输出结果:

代码语言:javascript
复制
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]

元组

代码语言:javascript
复制
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
)
}

输出结果:

代码语言:javascript
复制
first_item is ok
b_tuple.1 is 1
language is: en
country is: US
code is: 1

函数

代码语言:javascript
复制
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)
}

输出结果:

代码语言:javascript
复制
Greetings, pleased to meet you.
Indeed, 25 is the correct answer
sum is 46
Indeed, 12 is the correct answer

语句和表达式

代码语言:javascript
复制
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);
}

输出结果:

代码语言:javascript
复制
expression 4 + 5 evaluates to: 9

函数返回类型

代码语言:javascript
复制
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!")
}

输出结果:

代码语言:javascript
复制
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 ()

闭包

代码语言:javascript
复制
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));
}

输出结果:

代码语言:javascript
复制
22
297
541
110

摄氏度到华氏度转换

代码语言:javascript
复制
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)
}

条件执行

代码语言:javascript
复制
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);
}

输出结果:

代码语言:javascript
复制
x is 5
x_odd is even

多重条件(if/else if)

代码语言:javascript
复制
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");
}
}

输出结果:

代码语言:javascript
复制
x is less than y

循环赋值

代码语言:javascript
复制
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);
}

输出结果:

代码语言:javascript
复制
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循环

代码语言:javascript
复制
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
}

输出结果:

代码语言:javascript
复制
letter[0] is a
letter[1] is b
letter[2] is c
letter[3] is d
letter[4] is e

for循环

代码语言:javascript
复制
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 (&<NAME>)
// 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);
}
}

输出结果:

代码语言:javascript
复制
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

嵌套循环

代码语言:javascript
复制
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!("");
}
}

输出结果:

代码语言:javascript
复制
1 2 3
4 5 6
7 8 9
=======================
21 22 23
24 25 26
27 28 29

猜数游戏

代码语言:javascript
复制
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);
}

统计基础

代码语言:javascript
复制
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!");
}

输出结果:

代码语言:javascript
复制
Test passed!

作用域

代码语言:javascript
复制
fn main() {
let planet = "Dunya";
if true {
let planet = "Jupiter";
println!("planet is {}", planet);
}
println!("planet is {}", planet);
}

输出结果:

代码语言:javascript
复制
planet is Jupiter
planet is Dunya

变量可变性

代码语言:javascript
复制
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);
}

输出结果:

代码语言:javascript
复制
car is a Mitsubishi
car is a 1
car is a Mitsubishi

栈和堆

代码语言:javascript
复制
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);
}

输出结果:

代码语言:javascript
复制
=== 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有两种字符串类型。

代码语言:javascript
复制
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());
}

输出结果:

代码语言:javascript
复制
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

所有权

代码语言:javascript
复制
fn main() {
/* need to clean up allocated memory blocks no longer needed
in C/C++: malloc() and free() for manual memory mngt
other approach is garbage collection which is automatic */
/*
Rust uses OWNERSHIP ystem:
- variables are responsible for freeing their own resources
- every value is owned by only one variable at a time
- when owning variable goes out of scope the value is dropped
- there are ways to transfer ownership of a value from one variable to another
*/
let outer_planet: String;
let outer_galaxy: String;
let outer_planet_position: i32;
// inner code block scope
{
let inner_planet = String::from("Mercury");
println!("inner_planet is {}", inner_planet);
/*
because ownership mandates only one owner per value/data,
- inner_planet will no longer point to the String value on the heap
- transferring ownership from one variable to another is called a "move" in Rust
- this means that NO shallow copy of data STORED ON THE HEAP in Rust
(shallow copy = several variables pointing to same data in memory)
*/
// transferring ownership
outer_planet = inner_planet;
// can no longer use inner_planet variable after the move of ownership of string data
// println!("inner_planet is {}", inner_planet); // => will panic
let mut inner_galaxy = String::from("Milky Way");
println!("inner_galaxy is {}", inner_galaxy);
// to duplicate data, creates a deep copy of the String data

outer_galaxy = inner_galaxy.clone();
inner_galaxy.clear();
println!("inner_galaxy is now: {}", inner_galaxy);
println!("outer_galaxy is {}", outer_galaxy);
// integer data types live on the stack
let mut inner_planet_position = 1;
println!("inner_planet_position is {}", inner_planet_position);
/*
a copy of the integer data is created for the outer_planet_position
- ownership is respected (no shallow copy - only one variable per value at a time)
- generally STACK-ONLY data types (ie fixed size) are implicitly copied
when variable containing them is assigned to another variable
- data types stored om stack implement the trait that allow them to be copied rather than moved
*/
outer_planet_position = inner_planet_position;
inner_planet_position += 4;
println!("inner_planet_position is {}", inner_planet_position);
println!("outer_planet_position is {}", outer_planet_position);
}
println!("\nouter_planet is {}", outer_planet);
println!("outer_galaxy is {}", outer_galaxy);
println!("outer_planet_position is {}", outer_planet_position);
}

输出结果:

代码语言:javascript
复制
inner_planet is Mercury
inner_galaxy is Milky Way
inner_galaxy is now:
outer_galaxy is Milky Way
inner_planet_position is 1
inner_planet_position is 5
outer_planet_position is 1

所有权转移

代码语言:javascript
复制
fn main() {
let rocket_fuel = 1;
process_fuel(rocket_fuel);
println!("rocket_fuel is {}", rocket_fuel);
}
/*
because propellant is i32 so lives on the stack, the value is COPIED jn fn scope
*/
fn process_fuel(mut propellant: i32) {
// the copy is modified
propellant += 2;
println!("Processing propellant {}", propellant);
}

输出结果:

代码语言:javascript
复制
Processing propellant 3
rocket_fuel is 1
fn main() {
let mut arr_1: [u8; 2] = [33, 66];
// ////////////////
// fixed-length types (stored on the stack) are COPIED
// ////////////////
let arr_2 = arr_1;
println!("arr_1 is {:?}", arr_1);
arr_1 = [1, 2];
println!("arr_1 is now {:?}", arr_1);
println!("arr_2 is {:?}", arr_2);
// ////////////////
// mutable-length type values move the ownership to new variable
// ////////////////
let vec_1 = vec![3, 4];
let vec_2 = vec_1;
// can be no longer use the variable which ownership has been "moved"
// println!("vec_1 is {:?}", vec_1); // => wll panic
println!("vec_2 is {:?}", vec_2);
// to borrow value owned by a variable without moving ownership,
// use a reference to that value
let vec_4 = vec![5, 6, 7];
// borrowing value using a reference (&<NAME>)
let vec_5 = &vec_4;
println!("vec_4 is {:?}", vec_4);
println!("vec_5 is {:?}", vec_5);
}

输出结果:

代码语言:javascript
复制
arr_1 is [33, 66]
arr_1 is now [1, 2]
arr_2 is [33, 66]
vec_2 is [3, 4]
vec_4 is [5, 6, 7]
vec_5 is [5, 6, 7]

结构体

代码语言:javascript
复制
// used to create custom data type
struct Position {
longitude: f64,
latitude: f64,
}
// tuple struct
struct Signal(u8, bool, String);
struct Car {
model: String,
year: String,
used: bool,
}
// associate functions to struct
impl Car {
// construct car
fn new(m: &str, y: &str) -> Car {
Car {
model: m.to_string(),
year: y.to_string(),
used: false,
}
}
// self is equivalent to "this" is JavaScript
fn serialize(&self) -> String {
format!(
"model: {} - year: {} - used: {}",
self.model, self.year, self.used
)
}
// mutate state
fn marked_used(&mut self) {
self.used = true;
}
}
fn main() {
let mut pos_1 = Position {
latitude: 27.299112,
longitude: 95.387110,
};
println!(
"pos_1 is {:.3}, {:.3}",
pos_1.latitude,
pos_1.longitude
);
pos_1.latitude = 23.1111;
println!(
"pos_1 is now {:.3}, {:.3}",
pos_1.latitude,
pos_1.longitude
);
let mut s1 = Signal(0, true, String::from("ok"));
println!("s1 is {}, {}, {}", s1.0, s1.1, s1.2);
s1.0 = 23;
s1.1 = false;
s1.2 = String::from("NETERR");
println!("s1 is now {}, {}, {}", s1.0, s1.1, s1.2);
let car_1 = Car::new("QBC", "2133");
println!("car_1 is a {} of {}", car_1.model, car_1.year);
let is_used = if car_1.used == true {
"used"
} else {
"brand new"
};
println!("car_1 is {}", is_used);
println!("car_1 is {}", car_1.serialize());
let mut car_2 = Car::new("ZZ7", "2042");
println!("car_2 is a {}", car_2.serialize());
car_2.marked_used();
println!("car_2 is now {}", car_2.serialize());
}

输出结果:

代码语言:javascript
复制
os_1 is 27.299, 95.387
pos_1 is now 23.111, 95.387
s1 is 0, true, ok
s1 is now 23, false, NETERR
car_1 is a QBC of 2133
car_1 is brand new
car_1 is model: QBC - year: 2133 - used: false
car_2 is a model: ZZ7 - year: 2042 - used: false
car_2 is now model: ZZ7 - year: 2042 - used: true

枚举

代码语言:javascript
复制
enum Controller {
Turbo,
Up,
Down,
Left,
Right,
X,
Y,
A,
B,
}
fn push_button_notify(c: &Controller) {
// pattern mathing (equivalent to swith in JavaScript)
match c {
Controller::Turbo => println!("Turbo button pushed."),
Controller::Up => println!("Up button pushed."),
Controller::Down => println!("Down button pushed."),
Controller::Left => println!("Left button pushed."),
Controller::Right => println!("Right button pushed."),
Controller::Y => println!("Y button pushed."),
Controller::X => println!("X button pushed."),
Controller::A => println!("A button pushed."),
Controller::B => println!("B button pushed."),
}
}
fn main() {
let secret_push_combo = [
Controller::Up,
Controller::Left,
Controller::A,
Controller::Turbo,
Controller::Y,
Controller::B,
Controller::Turbo,
Controller::Down,
Controller::Right,
Controller::X,
];
for push in secret_push_combo.iter() {
push_button_notify(push);
}
}

输出结果:

代码语言:javascript
复制
Up button pushed.
Left button pushed.
A button pushed.
Turbo button pushed.
Y button pushed.
B button pushed.
Turbo button pushed.
Down button pushed.
Right button pushed.
X button pushed.

原文链接:https://itnext.io/deep-dive-into-rust-for-node-js-developers-5faace6dc71f 译文链接:https://mp.weixin.qq.com/s/kaPudEuA7O5a7j5dHRsJ4w

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-07-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Nodejs技术栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 创建一个Rust项目
  • 对数值输出进行高级格式化
  • 位操作(高级内容,可以跳过)
  • 语句和表达式
相关产品与服务
边缘可用区
腾讯云边缘可用区(TencentCloud Edge Zone,TEZ)是腾讯云的本地扩展,适用于解决计算、存储和服务可用性问题。腾讯云边缘可用区可为您带来云的诸多优势,例如弹性、可扩展性和安全性。借助腾讯云边缘可用区,您可以在靠近最终用户的地理位置运行对延迟敏感的应用程序,基本消除延迟问题。腾讯云边缘可用区提供与中心节点一致的体验,助力业务下沉,具备更低延时、更广覆盖、更少成本等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档