机器心脏报告
参加者:Si、Jamin
许多开发人员表示,他们可以在一天内学会Python,在两天内学会Go,但是一旦他们接触到Rust,他们就会意识到自己的风格有点不对劲。从语法到功能,它似乎会变得更加复杂。本文介绍Rust。作者声称,通过解析大量代码,你可以在“30 分钟”内开始使用Rust。
Rust 是一种注重安全性,尤其是并发安全性的系统编程语言。它支持函数式、命令式、通用编程范式等多范式语言,也被用作TensorFlow等深度学习框架的优秀前端语言。
Rust 在语法上与C 和C++ 类似,代码块由大括号和相同的控制流关键字分隔。然而,Rust 设计者希望在保证性能的同时提高内存安全性。 Rust 自2016 年以来一直开源。 Rust 在各种开发者调查中一直被誉为“最受欢迎的语言”,该开源项目目前拥有42,900 颗星。
《机器之心》的大多数读者都熟悉Python,但不太熟悉Rust。 Amos 最近发表的一篇博客文章指出,通过阅读他的作品,您可以在30 分钟内开始使用Rust。因此,在本文中,我不想专注于一个或几个重要概念,而是想通过包含各种关键字和符号的代码块来概述Rust 的各种功能。重要性。
在HackNews 上,很多开发者表示这个入门教程非常实用。他表示,Rust 的进入门槛已经比较高,随着各种复杂概念和功能的引入,很容易“退出”。因此,本基于示例代码的教程非常有用。
让我们从变量开始
您可以绑定变量:
让x; //声明’x’x=42。 //将42 分配给’x’。 //合并在一行上。
您可以使用: 指定变量的数据类型和数据类型注释。
let x: i32; //`i32` 是一个有符号的32 位整数x=42; //也是无符号的i8、i16、i32、u64、u128 x: i32=42;
如果你声明一个变量并在初始化它之前调用它,编译器会警告你:
let x;foobar(x); //error: 借用可能未初始化的变量: `x`x=42;
但是,执行以下操作是完全可以接受的:
let x;x=42;foobar(x); //`x` 的类型是从这里推断出来的
下划线代表特殊名称或“缺失的名称”。这与Python 的用法类似。
//42 是一个常量let 所以它*什么都不做* _=42; //这调用`get_thing` 但丢弃结果_=get_thing();
以下划线开头的名称是普通名称,但编译器不会警告您它们未被使用。
//我最终可能会使用`_x`,但代码正在开发中, //我现在只想摆脱编译器警告。让_x=42;
可以使用相同名称进行单独的绑定,并且第一个绑定变量将被取消。
let x=13;let x=x + 3;//如果在该行之后使用`x`,则只会引用第二个`x`, //第一个`x` 不再存在。
Rust 有一个元组类型,可以将其视为“不同数据类型的值的固定长度集合”。
let par=(‘a’, 17);pair.0; //这是’a’pair.1; //这是17。
如果你确实想设置pair的数据类型,你可以这样写:
考虑这对: (char, i32)=(‘a’, 17);
元组可以在赋值期间分解。也就是说,元组被分成单独的字段。
let (some_char, some_int)=(‘a’, 17);//现在`some_char` 是’a’ 并且`some_int` 是17
当函数返回元组时这很有用。
let (left, right)=slip.split_at(middle); 当然,分割元组时,可以只分割其中的一部分。
让(_,右)=slide.split_at(中);
分号标志着语句的结束。
设x=3;y=5;
不添加分号意味着该语句可以跨越多行。
让x=vec![1, 2, 3, 4, 5, 6, 7, 8] .iter() .map(|x| x + 3) .fold(0, |x, y| x + y) ;
功能即将到来
fn 声明一个函数。下面是一个空函数。
fngreet() { println!(‘你好!’);}
这是一个返回32 位有符号整数值的函数。箭头表示返回类型。
fn fair_dice_roll() – i32 { 4}
大括号表示具有自己作用域的代码块。
//这会打印“in”,然后打印“out”。 fn main() { let x=’out’; { //这是另一个`x’ let x=’in’ } println!
代码块也是表达式,这意味着它们的计算结果是一个值。
//this:let x=42; //等价于this:let x={ 42 }。
一个代码块可以包含多个语句。
let x={ let y=1; //第一个语句let z=2; //第二个语句y + z //这是评估整个块的结果。
这就是为什么“省略函数末尾的分号”相当于添加一个Retrun,如下所示:
fn fair_dice_roll() – i32 { return 4;}fn fair_dice_roll() – i32 { 4}
if 条件语句也是一个表达式。
fn Fair_dice_roll() – i32 { if Feeling_lucky { 6 } else { 4 }}
匹配匹配器也是一个表达式。
fn Fair_dice_roll() – i32 { 匹配Feeling_lucky { true=6, false=4, }}
点通常用于访问对象的字段。
let a=(10, 20);a.0; //这是10let amos=get_some_struct(); //这是’fasterthanlime’
或者调用对象的方法。
let Nick=’fasterthanlime’;nick.len(); //这是14
双冒号类似,但与命名空间一起使用。在此示例中,std 是crate(~ 库),cmp 是模块(~ 源文件),min 是函数。
让最小值=std:cmp:min(3, 8); //这是3。
您可以使用use 指令将名称“范围”到其他命名空间中。
usestd:cmp:min;letminimum=min(7, 1); //这是1 在use 指令中,大括号有不同的含义:“glob”,因此您可以同时导入min 和max。
//这有效:use std:cmp:min;usestd:cmp:max;//这也有效:use std:cmp:{min, max};//这也有效!use std333 6033 360{ cm p:min, cmp:max}; 通配符(*) 允许您从命名空间导入符号。
//这将`min` 和`max` 纳入范围,许多其他使用std:cmp:*。
类型也是命名空间和方法,可以像常规函数一样调用。
let x=’amos’.len(); //这是4 let x=str:len(‘amos’); //这也是4
虽然str 是原始数据类型,但默认情况下许多非原始数据类型也包含在范围内。
//`Vec` 是一个常规结构体,而不是原始typelet v=Vec:new();//这是完全相同的代码,但具有指向`Vec`let 的*完整*路径v=std:vec:Vec:new()
它起作用的原因是Rust 在每个模块的顶部插入以下内容。
使用std:prelude:v1:*。
我们来谈谈结构
使用struct 关键字声明结构。
struct Vec2 { x: f64, //64 位浮点数,又名“双精度” y: f64,}
可以使用结构语句对其进行初始化。
let v1=Vec2 { x: 1.0, y: 3.0 };let v2=Vec2 { y: 2.0, x: 4.0 };//顺序不重要,只有名称重要
有一个快捷方式可以从另一个结构体初始化该结构体的其余字段。
让v3=Vec2 { x: 14.0,v2};
这就是所谓的“结构更新语法”,只能用在最后一个位置,后面不能有逗号。
注意,其余字段可以代表所有字段。
让v4=Vec2 { .v3 };
元组等结构可以被破坏。例如,有效的let 模式是:
let (left, right)=slip.split_at(middle);let v=Vec2 { x: 3.0, y: 6.0 };let Vec2 { x, y }=v;//`x` 是3.0,`y` 当前是` 6.0`let Vec2 { x, }=v;//这会丢弃`v.y`
使用let 模式作为if 条件。
struct Number { od: bool, value: i32,}fn main() { let one=Number { od: true, value: 1 }; let Two=Number { od: false, value: 2 }; fn print_number(n: Number) { if let Number { od: true, value }=n { println!(‘奇数: {}’, value); else if let Number { od: false, value }=n { println!(‘偶数: {}’, value) }}//这将输出: //奇数: 1 //偶数: 2
多分支匹配也是一种条件模式,就像if let 一样。
fn print_number(n: Number) { match n { Number { od: true, value }=println!(‘odd: {}’, value), Number { od: false, value }=println!(‘偶数: {}’, value ), }}//这将打印与之前相同的内容
比赛必须是全方位的。至少一个条件分支必须匹配。
fn print_number(n: Number) { match n { Number { value: 1, }=println!(‘One’), Number { value: 2, }=println!(‘Two’), Number { value, }=println!(‘{}’, value), //如果最后一个臂不存在,则会出现编译时错误}}
fn print_number(n: Number) { 匹配n.value { 1=println!(‘一’), 2=println!(‘二’), _=println!(‘{}’, n.value), }}
类型别名
您可以使用type 关键字声明另一个类型的别名,并像使用真实类型一样使用该类型。例如,如果将数据类型Name 定义为字符串,则稍后可以直接使用该Name 类型。您可以在方法中声明各种数据类型。
struct Number { od: bool, value: i32,}impl Number { fn is_strictly_positive(self) – bool { self.value 0 }}fn main() { let negative_two=Number { od: false, value: -2, }; 正数? ‘, minus_two.is_strictly_positive()); //打印’positive? false’ { let n=Number { od: true, value: 17, }; //`n` 未声明为可变的,因此}fn main() { let n=Number { od: true, value: 17, }; n=Number { od: false, value: 22, }; //error: 不可变变量`n ` 不能分配两次。
mut 允许您使变量声明可变。
fn main() { let mut n=Number { od: true, value: 17, } n.value=19; //一切都好}
特征描述了多种数据类型的共同点。
Trait Signed { fn is_strictly_negative(self) – bool;}impl Signed for Number { fn is_strictly_negative(self) – bool { self.value 0 }}fn main() { let n=Number { od: false, value: -44 }; (‘{}’, n.is_strictly_negative()); //输出’true’。 impl i32 有符号{ fn is_strictly_negative(self) – bool { self 0 }}fn main() { let n: i32=-44; println!(‘{}’, n.is_strictly_negative()); std:ops:Neg for Number { type Output=Self fn neg(self) – Self { value: -self.value, od: self .odd, } }}fn main() { let a: i32=15; //`a` 被复制let c=a; //`a` 被再次复制}
下面的代码也有效。
fn print_i32(x: i32) { println!(‘x={}’, x);}fn main() { let a: i32=15; //复制`a` print_i32(a)/`a` 再次复制} fn main() { let n=Number { od: true, value: 51 }; //将`n` 移动到`m` let o=n;移动value: `n`}fn print_number(n: Number) { println!(‘{ } number {}’, if n.odd { ‘odd’ } else { ‘even’ }, n.value);}fn main( ) { let n=Number { od: true, value: 51 };已移动print_number(n) //error: 使用移动后的值: `n`}fn print_number(n: Number) { println !(‘{} number {}’, if n.odd { ‘odd’ } else { ‘even’ } , n.value);}fn main() { let n=Number { od: true, value: 51 }; //`n` 是调用//`n` 又被借用了}fn invert(n: mut Number) { n.value=-n.value;}fn print_number(n: Number) { println!(‘{ } number {}’, if n.odd { ‘odd’ } else { ‘even’ }, n.value );}fn main() { //` n` 这次可以改变let mut n=Number { od: true, value: 51 }; //`n 是可变借用的- 一切都是显式的print_number(n);}//note: `Copy ` 还必须实现`Clone` impl std:clone:Clone for Number { fn clone(self) – Self { Self { .*self } }}impl std:marker:Copy for Number {}
克隆仍可用于:
fn main() { let n=Number { od: true, value: 51 }; let m=n.clone(); let o=n.clone();}fn main() { let n=Number { od: true, value: 51 }; let m=n; //`m` 是`n` 的副本let o=n` 既不移动也不借用。
有一些共同特征可以使用派生属性自动实现。
#[derive(Clone, Copy)]struct Number { od: bool, value: i32,}//这会扩展为`impl Clone for Number` 和`impl Copy for Number` 块。
在整个教程中,似乎有很多代码用于解释各种Rust 语句和用法。虽然博客结构可能看起来不是很清晰,但是示例驱动的代码学习肯定是高效的。尤其是有一定编程基础的同学,可以快速掌握Rust语言的特性和逻辑。
最后,本文不介绍博客的全部内容。如果您想开始使用Rust 语言,我建议您查看原始博客。
原创文章,作者:小条,如若转载,请注明出处:https://www.sudun.com/ask/85085.html