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 <strong>name</strong> == "<strong>main</strong>":
    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(<strong>name</strong>)


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


if <strong>name</strong> == '<strong>main</strong>':
    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 <strong>name</strong> == "<strong>main</strong>":
    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 <strong>init</strong>(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 <strong>init</strong>(self, name, age):
        self.name = name
        self.age = age

    def <strong>repr</strong>(self):
      return str(self.<strong>dict</strong>)

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 }
}