Python与Rust语法比较

可以复制粘贴本文代码:

  • 在https://play.rust-lang.org/ 运行 Python
  • 在https://repl.it/languages/python3 中运行 Rust 示例

安装新的库/包
Python
$ pip install foo 

Rust
$ cargo install foo

运行编译:
Python
$ python my_python_program.py 

Rust
$ cargo run
在 Rust 中,有一个 --release 标志可以在编译时进行更多优化,但编译时间会更长。
$ cargo run --release


你好世界
Hello World
Python

if __name__ == "__main__":
    print(
"Hello, World")

Rust

fn main() {
  println!("Hello, World");
}


类型和声明
创建新对象、基本原始类型值和数据结构。
Python

age = 80
name = 'daffy'
weight = 62.3
loons = ['bugs', 'daffy', 'taz']
ages = {  # Ages for 2017
    'daffy': 80,
    'bugs': 79,
    'taz': 63,
}

Rust

use std::collections::HashMap;

fn main() {
    let age = 80;
    let name = "daffy";
    let weight = 62.3;
    let mut loons = vec![
"bugs", "daffy", "taz"];

    let mut ages = HashMap::new();  
// Ages for 2017
    ages.insert(
"daffy", 80);
    ages.insert(
"bugs", 79);
    ages.insert(
"taz", 63);
}


定义一个函数
定义一个接收 2 个整数参数并返回其和的函数。

Python

def add(a, b):
    """Adds a to b"""
    return a + b

带有类型注释的 Python

它看起来更类似于 Rust。

def add(a: int, b: int) -> int:
    """Adds a to b"""
    return a + b

Rust

/// Adds a to b
fn add(a: i32, b: i32) -> i32 {
  a + b
}


列表/切片
创建列表、添加新元素、获取列表长度、按索引分片、使用 for 循环迭代以及使用枚举器迭代。

Python

names = ['bugs', 'taz', 'tweety']
print(names[0])  # bugs
names.append('elmer')
print(len(names))  # 4
print(names[2:])  # ['tweety', 'elmer']

for name in names:
    print(name)

for i, name in enumerate(names):
    print('{} at {}'.format(name, i))


Rust

fn main() {
    let mut names = vec!["bugs", "taz", "tweety"];
    println!(
"{}", names[0]);  // bugs
    names.push(
"elmer");
    println!(
"{}", names.len());  // 4
    println!(
"{:?}", &names[2..]);  // ["tweety", "elmer"]

    for name in &names {
        println!(
"{}", name);
    }

    for (i, name) in names.iter().enumerate() {
        println!(
"{} at {}", i, name);
    }
}

.step_by() 相当于 python 的 range/xrange 步长参数。
python:

for i in range(0,10,2):
   print(i) # 0, 2, 4, 6, 8

rust:

for i in (0..10).step_by(2) {
    println!("{}", i);  // 0, 2, 4, 6, 8
}

字典/地图
创建新字典(哈希映射)、添加新键和值、更改值、通过键获取、检查键是否包含等。
Python

创建新二进制文件并填充
ages = {}
ages['daffy'] = 80
ages['bugs'] = 79
ages['taz'] = 63

# 或使用 for 循环进行同样的操作
ages = {}
for name, age in [("daffy", 80), ("bugs", 79), ("taz", 63)]:
    ages[name] = age

# or initializing from a list
ages = dict([(
"daffy", 80), ("bugs", 79), ("taz", 63)])

或在创建时传递键值
ages = {  # Ages for 2017
    'daffy': 80,
    'bugs': 79,
    'taz': 63,
}

ages['elmer'] = 80
print(ages['bugs'])  # 79
print('bugs' in ages)  # True

del ages['taz']

for name in ages:  # Keys
    print(name)

for name, age in ages.items():  # Keys & values
    print('{} is {} years old'.format(name, age))

Rust代码

use std::iter::FromIterator;
use std::collections::HashMap;

fn main() {

    // 创建新的 HashMap 并填充它
    let mut ages = HashMap::new();  
// Ages for 2017
    ages.insert(
"daffy", 80);
    ages.insert(
"bugs", 79);
    ages.insert(
"taz", 63);

   
// 或使用循环进行同样的操作
    let mut ages = HashMap::new();
    for &(name, age) in [(
"daffy", 80), ("bugs", 79), ("taz", 63)].iter() {
       
// For non-Copy data, remove & and use iter().clone()
        ages.insert(name, age);
    }

   
// 或从数组初始化
    let mut ages: HashMap<&str, i32> =  
// Ages for 2017
        [(
"daffy", 80), 
         (
"bugs", 79), 
         (
"taz", 63)]
        .iter().cloned().collect();

   
// 或从 Vec(迭代器)初始化
    let mut ages: HashMap<&str, i32> =  
// Ages for 2017
        HashMap::from_iter(
            vec![
               (
"daffy", 80),
               (
"bugs", 79),
               (
"taz", 63)
            ]
        );

    ages.insert(
"elmer", 80);
    println!(
"{}", ages["bugs"]);  // 79
    println!(
"{}", ages.contains_key("bugs")); // true
    ages.remove(
"taz");


    for name in ages.keys() {  
// Keys
      println!(
"{}", name);
    }

    for (name, age) in &ages {  
// Keys & values
      println!(
"{} is {} years old", name, age);
    }

}

在 Rust 中用 Pythonic 替代 dict/map
你可以使用 maplit crate 来加载 hashmap! 宏,以获得高效的糖化(又称 Pythonic)语法!

# Cargo.toml
[dependencies]
maplit = "*"


#[macro_use] extern crate maplit;

let map = hashmap!{
    "daffy" => 80,
   
"bugs" => 79,
   
"taz" => 63,
};

集合/哈希集
创建集合(由唯一键组成的哈希值),添加新键并计算交集、差集和合集

Python

# 创建和填充
colors = set()
colors.add("red")
colors.add(
"green")
colors.add(
"blue")
colors.add(
"blue")

# using literal syntax
colors = {'red', 'green', 'blue', 'blue'}

# from an iterator
colors = set(['red', 'green', 'blue', 'blue'])


# deduplication
print(colors)  # {
"blue", "green", "red"}

# operations
colors = {'red', 'green', 'blue', 'blue'}
flag_colors = {
"red", "black"}

# difference
colors.difference(flag_colors)  # {'blue', 'green'}

# 对称差
colors.symmetric_difference(flag_colors)  # {'black', 'blue', 'green'}

# 交叉点intersection
colors.intersection(flag_colors)  # {'red'}

# union
colors.union(flag_colors)  # {'black', 'blue', 'green', 'red'}

Rust
use std::collections::HashSet;
use std::iter::FromIterator;

fn main() {

   
// 创建和填充 - 类型推断
    let mut colors = HashSet::new();
    colors.insert(
"red");
    colors.insert(
"green");
    colors.insert(
"blue");
    colors.insert(
"blue");

   
// from an iterator -显式类型
    let mut colors: HashSet<&str> = HashSet::from_iter(vec![
"red", "green", "blue", "blue"]);

   
// 重复数据删除deduplication
    println!(
"{:?}", colors); // {"blue", "green", "red"}

   
// Operations
    let mut colors: HashSet<&str> = HashSet::from_iter(vec![
"red", "green", "blue", "blue"]);
    let mut flag_colors: HashSet<&str> = HashSet::from_iter(vec![
"red", "black"]);

   
// difference
    colors.difference(&flag_colors);
// ["green", "blue"]

   
// 对称差symmetric difference
    colors.symmetric_difference(&flag_colors);
// ["blue", "green", "black"]

   
// intersection
    colors.intersection(&flag_colors);
// ["red"]

   
// union
    colors.union(&flag_colors);
// ["red", "blue", "green", "black"]
}

或使用 maplit crate 进行语法润色

#[macro_use] extern crate maplit;

let colors = hashset!{"red", "green", "blue", "blue"};

While 和 For 循环
循环,直到满足某个条件或遍历一个可迭代对象。
Python

# While loop

counter = 0
while counter < 10:
    print(counter)
    counter += 1

# infinite while loop
while True:
    print("loop Forever!")

# infinite while loop with break
counter = 0
while True:
    print(counter)
    counter += 1
    if counter >= 10:
        break


# while loop with continue
counter = 0
while True:
    counter += 1
    if counter == 5:
        continue
    print(counter)
    if counter >= 10:
        break

# For loop over a list
for color in [
"red", "green", "blue"]:
    print(color)

# Enumerating indexes
for  i, color in enumerate([
"red", "green", "blue"]):
    print(f
"{color} at index {i}")

# For in a range
for number in range(0, 100):
    print(number)  # from 0 to 99


Rust

fn main() {

    // While loop
    let mut counter = 0;
    while counter < 10 {
        println!(
"{}", counter);
        counter += 1;
    }

   
// infinite while loop
    loop {
        println!(
"Loop forever!");
    }

   
// infinite while loop with break
    let mut counter = 0;
    loop {
        println!(
"{}", counter);
        counter += 1;
        if counter >= 10 { break; }
    }

   
// infinite while loop with continue
    let mut counter = 0;
    loop {
        counter += 1;
        if counter == 5 { continue; }
        println!(
"{}", counter);
        if counter >= 10 { break; }
    }

   
// for loop over a list
    for color in [
"red", "green", "blue"].iter() {
        println!(
"{}", color);
    }

   
// Enumerating indexes
    for (i, color) in [
"red", "green", "blue"].iter().enumerate() {
        println!(
"{} at index {}", color, i);
    }

   
// for in a range
    for number in 0..100 {
        println!(
"{}", number);  // from 0 to 99
    }
}

Rust 具有 Python 所没有的循环功能:Loop Labels循环标签

'outer: for x in 0..10 {
    'inner: for y in 0..10 {
        if x % 2 == 0 { continue 'outer; } // continues the loop over x
        if y % 2 == 0 { continue 'inner; }
// continues the loop over y
        println!(
"x: {}, y: {}", x, y);
    }
}

文件
读取文本文件并逐行打印内容,最后正确关闭文件。

Python

from pathlib import Path

with Path("/tmp/song.txt").open() as fp:
    #  Iterate over lines
    for line in fp:
        print(line.strip())


Rust

use std::io::{BufReader, BufRead};
use std::fs::File;
use std::path::Path;


fn main () {
    let fp = File::open(Path::new("/tmp/song.txt")).unwrap();
    let file = BufReader::new(&fp);
    for line in file.lines() {
       
//  Iterate over lines
        println!(
"{}", line.unwrap());
    }
}

异常/返回错误
期望出现异常并识别错误。
Python

def div(a, b):
    if b == 0:
        raise ValueError("b can't be 0")
    return a / b

# ...

try:
    div(1, 0)
except ValueError:
    print('An error occurred!')

Rust

fn div(a: i32, b: i32) -> Result<i32, &'static str> {
    if b == 0 {
        Err("b can't be 0")
    } else {
        Ok(a / b)
    }
}

fn main() {
    match div(1, 0) {
        Ok(_) => {},
        Err(_) => println!(
"An error occurred!"),
    };
}


并发性
Python

thr = Thread(target=add, args=(1, 2), daemon=True)
thr.start()

Rust

use std::thread;

[code]thread::spawn(|| {
        add(5,5);
    });
[/code]

线程间通信
管理线程之间的数据上下文。

Python

from queue import Queue
queue = Queue()
# ...
# Send message from a thread
queue.put(353)


# ...
# Get message to a thread
val = queue.get()


Rust

use std::thread;
use std::sync::mpsc;

fn main() {
    let (tx, rx) = mpsc::channel();

    let sender = thread::spawn(move || {
        let val = String::from("hi");
        tx.send(val.clone()).unwrap();
        println!(
"Sent {}", val);
    });

    let receiver = thread::spawn(move || {
        let received = rx.recv().unwrap();
        println!(
"Received: {}", received);
    });

    sender.join();
    receiver.join();
}

排序
对列表进行排序、反转和使用按键。
Python

names = ['taz', 'bugs', 'daffy']

# Lexicographical order
names.sort()

# Reversed lexicographical order
names.sort(reverse=True)

# Sort by length
names.sort(key=len)

Rust

fn main() {
    let mut names = ["taz", "bugs", "daffy"];

   
// Lexicographical order
    names.sort();

   
// Reversed lexicographical order
    names.sort_by(|a, b| b.cmp(a));

   
// Sort by length
    names.sort_by_key(|a| a.len());
}


带有 Flask / Rocket 的 Web 应用程序
Python

from flask import Flask

app = Flask(__name__)


@app.route('/')
def index():
    return 'Hello Python'


if __name__ == '__main__':
    app.run(port=8080)

Rust

#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

#[get("/")]
fn index() -> &'static str {
   
"Hello Rust"
}

fn main() {
    rocket::ignite().mount(
"/", routes![index]).launch();
}


具有错误处理功能的 HTTP 请求
Python使用 requests

import requests

url = 'https://httpbin.org/ip'

try:
    resp = requests.get(url)
except HTTPError as err:
    msg = f
"error: cannot get {url} - {err}"
    raise SystemExit(msg)

assert resp.status_code == 200

print(f
"The response content is: {resp.content}")

Rust使用reqwest

extern crate reqwest;
use std::io::Read;

fn main() {
    let url = "https://httpbin.org/ip";

    let mut resp = match reqwest::get(url) {
        Ok(response) => response,
        Err(e) => panic!(
"error: could not perform get request {}", e),
    };

    assert!(resp.status().is_success());

    let mut content = String::new();
    resp.read_to_string(&mut content).expect(
"valid UTF-8");

    println!(
"The response content is: {}", content);
}

多线程HTTP爬虫
使用requests

from concurrent.futures import ThreadPoolExecutor
import requests


URLS = (
    "https://httpbin.org/html",
   
"https://httpbin.org/links/10/0",
   
"https://httpbin.org/robots.txt",
   
"https://httpbin.org/user-agent",
   
"https://httpbin.org/links/10/0",
   
"https://httpbin.org/robots.txt",
   
"https://httpbin.org/xml",
   
"https://httpbin.org/redirect/1",
   
"https://httpbin.org/redirect/2",
   
"https://httpbin.org/cookies",
   
"https://httpbin.org/basic-auth/user/passwd",
   
"https://httpbin.org/gzip",
)


def crawl_worker(url):
    try:
        print(f
"Response of url: {url} is {requests.get(url).status_code}")
    except Exception:
        print(
"Failed to get url.")


if __name__ ==
"__main__":
    with ThreadPoolExecutor() as executor:
        executor.map(crawl_worker, URLS)

Rust使用reqwest

extern crate reqwest;
use std::thread;


fn crawl_worker(url: &str) {
    let parsed_url = reqwest::Url::parse(url).expect("Bad url format.");
    let response = reqwest::get(parsed_url).expect(
"Failed to get url.");
    println!(
"Response of url: {} is {:?}", url, response.status().to_string());
}


fn main() {
    let urls = vec![
       
"https://httpbin.org/html",
       
"https://httpbin.org/links/10/0",
       
"https://httpbin.org/robots.txt",
       
"https://httpbin.org/user-agent",
       
"https://httpbin.org/links/10/0",
       
"https://httpbin.org/robots.txt",
       
"https://httpbin.org/xml",
       
"https://httpbin.org/redirect/1",
       
"https://httpbin.org/redirect/2",
       
"https://httpbin.org/cookies",
       
"https://httpbin.org/basic-auth/user/passwd",
       
"https://httpbin.org/gzip",
    ];
    let mut queue = vec![];

    for url in urls {
        queue.push(thread::spawn(move || {
            crawl_worker(url);
        }));
    }

    for job in queue {
        let _ = job.join();
    }
}


JSON 编码和解码

Python

import json

# Decode/Deserialize
data = '''{
    "name": "bugs",
   
"age": 76
}'''

person = json.loads(data)

# 与其他 Python 数据结构一样进行操作
print(f
"{person['name']} was born {person['age']} years ago")

# Encode/Serialize
serialized = json.dumps(obj)
print(f
"The serialized value is: {serialized}")

Rust

extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate serde_derive;

#[derive(Serialize, Deserialize)]
struct Person {
    name: String,
    age: u8,
}

fn main() {
    // Decode/Deserialize
    let data = r#
"{"name": "bugs", "age": 76}"#;

    let p: Person = match serde_json::from_str(data) {
        Ok(person) => person,
        Err(e) => panic!(
"error: could not deserialize: {}", e),
    };

   
// 就像使用其他 Rust 数据结构一样。
    println!(
"{} was born {} years ago.", p.name, p.age);

   
// Encode/Serialize
    let serialized = serde_json::to_string(&p).unwrap();
    println!(
"The serialized value is: {}", serialized);
}


面向对象
Python:

class Cat:
    def __init__(self, name):
        self.name = name

    def greet(self, other):
        print("Meow {}, I'm {}".format(other, self.name))

# ...

grumy = Cat('Grumpy')
grumy.greet('Garfield')  # Meow Garfield, I'm Grumpy

Rust

struct Cat {
    name: String
}

impl Cat {

    pub fn new<S>(name: S) -> Cat where S: Into<String> {
        Cat { name: name.into() }
    }
    
    pub fn greet<S: Into<String>>(&self, other:S) {
        println!("Meow {}, I'm {}", other.into(), self.name);
    }     
    
}

fn main() {
    let grumpy = Cat::new(
"Grumpy");
    grumpy.greet(
"Garfield");  // Meow Garfield, I'm Grumpy
}

注意:在 Rust 中,最好避免使用字符串类型的 API,因此在上面的示例中,我们最好让 garfield = Cat::new("Garfield") 并接受 Cat 的实例作为其他参数。

打印调试/日志对象
打印格式化对象调试信息

Python

class Actor:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
      return str(self.__dict__)

daffy = Actor(
    name='Daffy',
    age=80,
)

print('{!r}'.format(daffy))  # {'name': 'Daffy', 'age': 80}

Rust


#[derive(Debug)]
struct Actor {
    name: String,
    age: i32
}

fn main() {
    let daffy = Actor {name: "Daffy".into(), age: 80};
    println!(
"{:#?}", daffy);   // Actor {name: "Daffy", age: 80 }
}