我的编程空间,编程开发者的网络收藏夹
学习永远不晚

针对JavaScript开发人员的Rust简介

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

针对JavaScript开发人员的Rust简介

Rust是2010年起源于Mozilla Research的一种编程语言。如今,所有大公司都在使用它。

亚马逊和微软都认可它是其系统中C / C ++的最佳替代品,但是Rust并不止于此。像Figma和Discord这样的公司现在也通过在客户端应用中使用Rust来引领潮流。

本篇Rust教程旨在简要介绍Rust,如何在浏览器中使用它,以及何时应该考虑使用它。我将从比较Rust和JavaScript开始,然后引导你完成Rust在浏览器中运行的步骤。最后,我将介绍一个使用Rust和JavaScript的COVID simulator web应用程序的快速性能评估。

简而言之

Rust在概念上与JavaScript非常不同。但也有相似之处需要指出,让我们来看看问题的两面。

相似之处

这两种语言都有一个现代化的包管理系统。JavaScript有npm,Rust有Cargo。Rust有 Cargo.toml 来代替 package.json 进行依赖管理。要创建一个新的项目,使用 cargo init,要运行它,使用 cargo run。不太陌生吧?

Rust中有许多很酷的功能,你已经从JavaScript中知道了,只是语法略有不同。利用这个常见的JavaScript模式,对数组中的每个元素都应用一个闭包:

  1. let staff = [ 
  2.    {name"George", money: 0}, 
  3.    {name"Lea", money: 500000}, 
  4. ]; 
  5. let salary = 1000; 
  6. staff.forEach( (employee) => { employee.money += salary; } ); 

在Rust中,我们可以这样写:

  1. let salary = 1000; 
  2. staff.iter_mut().for_each(  
  3.     |employee| { employee.money += salary; } 
  4. ); 

诚然,习惯这种语法需要时间,用管子( | )代替括号。但在克服了最初的尴尬之后,我发现它比另一组括号读起来更清晰。

再举一个例子,这是JavaScript中的对象解构:

  1. let point = { x: 5, y: 10 }; 
  2. let {x,y} = point; 

同样在Rust中:

  1. let point = Point { x: 5, y: 10 }; 
  2. let Point { x, y } = point; 

主要的区别是,在Rust中我们必须指定类型(Point),更普遍的是,Rust需要在编译时知道所有类型。但与大多数其他编译语言不同的是,编译器尽可能自己推断类型。

为了进一步解释这个问题,下面是在C++和许多其他语言中有效的代码。每个变量都需要明确的类型声明。

  1. int a = 5; 
  2. float b = 0.5; 
  3. float c = 1.5 * a; 

在JavaScript以及Rust中,这段代码是有效的:

  1. let a = 5; 
  2. let b = 0.5; 
  3. let c = 1.5 * a; 

共享功能不胜枚举:

  • Rust具有 async + await 语法。
  • 数组可以像让 let array = [1,2,3] 一样简单地创建。
  • 代码按模块组织,有明确的导入和导出。
  • 字符串是用Unicode编码的,处理特殊字符没有问题。

我可以继续列举下去,但我想我的观点现在已经很清楚了。Rust有一系列丰富的功能,这些功能在现代JavaScript中也有使用。

不同点

Rust是一种编译语言,这意味着没有运行时可以执行Rust代码。一个应用程序只能在编译器(rustc)完成它的魔法之后运行。这种方法的好处通常是更好的性能。

幸运的是,Cargo为我们解决了调用编译器的问题。而有了webpack,我们还可以将 Cargo 隐藏在 npm run build 后面。有了这个指南,只要为项目设置好Rust,就可以保留Web开发者的正常工作流程。

Rust 是一种强类型语言,这意味着在编译时所有类型必须匹配。例如,你不能调用一个参数类型错误或参数数量错误的函数。编译器会在你运行时遇到这个错误之前为你捕捉到它。显而易见的比较是TypeScript,如果你喜欢TypeScript,那么你很可能会喜欢Rust。

但别担心:如果你不喜欢TypeScript,Rust可能还是适合你。Rust 是近几年从头开始构建的,它考虑到了过去几十年来人类在编程语言设计方面所学到的一切。其结果是一种令人耳目一新的简洁语言。

Rust中的模式匹配是我最喜欢的一个特征,其他语言有 switch 和 case 来避免像这样的长链:

  1. if ( x == 1) {  
  2.   // ...  
  3. else if ( x == 2 ) { 
  4.   // ... 
  5. else if ( x == 3 || x == 4 ) { 
  6.   // ... 
  7. } // ... 

Rust使用了如下更优雅的匹配项:

  1. match x { 
  2.   1 => { }, 
  3.   2 => { }, 
  4.   3 | 4 => { }, 
  5.   5...10 => { }, 
  6.   _ => {  } 

我认为这是非常整洁的,我希望JavaScript开发人员也能欣赏这种语法扩展。

不幸的是,我们还得谈谈Rust的黑暗面。直言不讳地说,使用严格的类型系统有时会让人感觉非常繁琐。如果你认为C++或Java的类型系统很严格,那么请准备好迎接Rust的艰难之旅吧。

就我个人而言,我很喜欢Rust这部分。我依赖于严格的类型系统,因此可以关闭大脑的一部分——每当我发现自己在编写JavaScript时,大脑的一部分就会剧烈地兴奋起来。但是我知道对于初学者来说,总是和编译器作对是很烦人的。我们将在稍后的Rust教程中看到一些。

Hello Rust

现在,让我们用Rust在浏览器中运行一个 hello world ,我们首先要确保所有必要的工具都已安装。

工具

使用rustup安装Cargo + rustc。 Rustup是推荐的安装Rust的方法,它将安装最新的稳定版Rust的编译器(rustc)和包管理器(Cargo)。它将安装Rust最新稳定版本的编译器(rustc)和包管理器(Cargo)。它还可以管理beta版和每夜构建版,但对于本例来说,这不是必需的。

  • 在终端机上输入 cargo --version 来检查安装情况,你应该可以看到 cargo 1.48.0 (65cbdd2dc 2020-10-14) 这样的内容。
  • 还要检查Rustup:rustup --version 应该产生 rustup 1.23.0(00924c9ba 2020-11-27)。

安装wasm-pack。 这是为了将编译器与npm集成。

  • 通过输入 wasm-pack --version 来检查安装,这应该为您提供 wasm-pack 0.9.1 之类的东西。

我们还需要Node和npm。我们有一篇完整的文章[1]解释了安装这两个的最佳方法。

编写Rust代码

现在一切都安装好了,让我们来创建项目。最终的代码也可以在这个GitHub仓库[2]中找到。我们从一个可以编译成npm包的Rust项目开始,之后会有导入该包的JavaScript代码。

要创建一个名为 hello-world 的Rust项目,请使用 cargo init --lib hello-world。这将创建一个新目录并生成Rust库所需的所有文件:

  1. ├──hello-world 
  2.     ├── Cargo.toml 
  3.     ├── class="lazy" data-src 
  4.         ├── lib.rs 

Rust代码将放在 lib.rs 中,在此之前我们必须调整 Cargo.toml。它使用 TOML[3] 定义了依赖关系和其他包的信息。如果想在浏览器中看到hello world,请在 Cargo.toml 中的某个地方添加以下行数(例如,在文件的最后)。

  1. [lib] 
  2. crate-type = ["cdylib"

这告诉编译器在C兼容模式下创建一个库。显然我们在我们的例子中没有使用C。C-compatible只是意味着不是Rust专用的,这是我们使用JavaScript中的库所需要的。

我们还需要两个外部库,将它们作为单独的一行添加到依赖关系部分。

  1. [dependencies] 
  2. wasm-bindgen = "0.2.68" 
  3. web-sys = {version = "0.3.45", features = ["console"]} 

这些都是来自 crates.io[4] 的依赖项,它是 Cargo 使用的默认包仓库。

wasm-bindgen[5]是必要的,以创建一个我们以后可以从JavaScript中调用的入口点。(你可以在这里找到完整的文档。)值 ”0.2.68" 指定了版本。

web-sys[6]包含了所有Web API的Rust绑定,它将使我们能够访问浏览器控制台。请注意,我们必须明确地选择控制台功能,我们最终的二进制文件将只包含这样选择的Web API绑定。

接下来是 lib.rs 内部的实际代码。自动生成的单元测试可以删除。只需使用以下代码替换文件的内容:

  1. use wasm_bindgen::prelude::*; 
  2. use web_sys::console; 
  3.  
  4. #[wasm_bindgen] 
  5. pub fn hello_world() { 
  6.     console::log_1("Hello world"); 

顶部的 use 语句是用于从其他模块导入项目。这与JavaScript中的 import 类似)。

pub fn hello_world(){...} 声明一个函数。pub 修饰符是“public”的缩写,作用类似于JavaScript中的 export。注释 #[wasm_bindgen] 特定于Rust编译为[WebAssembly (Wasm)](https://webassembly.org/ "wasm_bindgen] 特定于Rust编译为[WebAssembly (Wasm "wasm_bindgen] 特定于Rust编译为[WebAssembly (Wasm)")")。我们在这里需要它来确保编译器将包装函数公开给JavaScript。

在功能主体中,“Hello world”被打印到控制台上。Rust中的 console :: log_1() 是对 console.log() 的调用的包装。

你是否注意到函数调用中的 _1 后缀?这是因为JavaScript允许使用可变数量的参数,而Rust不允许。为了解决这个问题, wasm_bindgen 为每种参数数量生成一个函数。是的,这很快就会变得丑陋!但这有效。在web-sys文档[7]中提供了一个可以在Rust控制台中调用的完整函数列表。

现在我们应该已经一切就绪,试着用下面的命令编译它。这将下载所有的依赖项并编译项目,第一次可能会花一些时间。

  1. cd hello-world 
  2. wasm-pack build 

哈!Rust编译器对我们不满意。

  1. error[E0308]: mismatched types 
  2.  --> class="lazy" data-src\lib.rs:6:20 
  3.   | 
  4. 6 |     console::log_1("Hello world"); 
  5.   |                    ^^^^^^^^^^^^^ expected struct `JsValue`, found `str` 
  6.   | 
  7.   = note: expected reference `&JsValue` 
  8.              found reference `&'static str 

注意:如果您看到其他错误(error: linking with cc failed: exit code: 1)并且你使用的是Linux,则说明缺少交叉编译依赖性。sudo apt install gcc-multilib 应该可以解决此问题。

正如我前面提到的,编译器很严格。当它期望一个 JsValue 的引用作为一个函数的参数时,它不会接受一个静态字符串。为了满足编译器的要求,必须进行显式转换。

  1. console::log_1(&"Hello world".into()); 

方法 [into()](https://doc.rust-lang.org/std/convert/trait.Into.html "into( "into()")") 将一个值转换为另一个值。Rust 编译器很聪明,它可以推迟哪些类型参与转换,因为函数签名只留下了一种可能性。在这种情况下,它将转换为 JsValue,这是一个由JavaScript管理的值的包装类型。然后,我们还得加上 &,通过引用而不是通过值来传递,否则编译器又会抱怨。

尝试再次运行 wasm-pack build,如果一切顺利,则最后一行应如下所示:

  1. [INFO]: :-) Your wasm pkg is ready to publish at /home/username/intro-to-rust/hello-world/pkg. 

如果你能走到这一步,你现在就可以手动编译Rust了。下一步,我们将把它与npm和webpack集成,后者将自动为我们完成这项工作。

JavaScript整合

在这个例子中,我决定将 package.json 放在 hello-world 目录内。我们也可以为Rust项目和JavaScript项目使用不同的目录,这是个口味问题。

以下是我的 package.json 文件。遵循的最简单方法是将其复制并运行 npm install,或者运行 npm init 并仅复制 dev 依赖项:

  1.     "name""hello-world"
  2.     "version""1.0.0"
  3.     "description""Hello world app for Rust in the browser."
  4.     "main""index.js"
  5.     "scripts": { 
  6.         "build""webpack"
  7.         "serve""webpack serve" 
  8.     }, 
  9.     "author""Jakob Meier "
  10.     "license""(MIT OR Apache-2.0)"
  11.     "devDependencies": { 
  12.         "@wasm-tool/wasm-pack-plugin""~1.3.1"
  13.         "@webpack-cli/serve""^1.1.0"
  14.         "css-loader""^5.0.1"
  15.         "style-loader""^2.0.0"
  16.         "webpack""~5.8.0"
  17.         "webpack-cli""~4.2.0"
  18.         "webpack-dev-server""~3.11.0" 
  19.     } 

如你所见,我们使用的是webpack 5。Wasm-pack也可以和旧版本的webpack一起使用,甚至可以不使用捆绑程序。但每个设置的工作方式都有些不同,我建议你在跟随这个Rust教程时使用完全相同的版本。

另一个重要的依赖项是 wasm-pack-plugin。这是一个Webpack插件,专门用于加载使用wasm-pack构建的Rust软件包。

继续,我们还需要创建 webpack.config.js 文件来配置webpack。它应该是这样的:

  1. const path = require('path'); 
  2. const webpack = require('webpack'); 
  3. const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin"); 
  4.  
  5. module.exports = { 
  6.     entry: './class="lazy" data-src/index.js'
  7.     output: { 
  8.         path: path.resolve(__dirname, 'dist'), 
  9.         filename: 'index.js'
  10.     }, 
  11.     plugins: [ 
  12.         new WasmPackPlugin({ 
  13.             crateDirectory: path.resolve(__dirname, "."
  14.         }), 
  15.     ], 
  16.     devServer: { 
  17.         contentBase: "./class="lazy" data-src"
  18.         hot: true
  19.     }, 
  20.     module: { 
  21.         rules: [{ 
  22.             test: /\.css$/i, 
  23.             use: ["style-loader""css-loader"], 
  24.         }, ] 
  25.     }, 
  26.     experiments: { 
  27.         syncWebAssembly: true
  28.     }, 
  29. }; 

所有的路径都配置为Rust代码和JavaScript代码并排。index.js 将在 class="lazy" data-src 文件夹中,紧挨着 lib.rs。如果你喜欢不同的设置,可以随时调整这些。

你还会注意到,我们使用webpack experiments[8],这是webpack 5引入的新选项。请确保将 syncWebAssembly 设置为true。

最后,我们必须创建JavaScript入口点 class="lazy" data-src/index.js:

  1. import("../pkg").catch(e => console.error("Failed loading Wasm module:", e)).then
  2.     rust => 
  3.         rust.hello_world() 
  4. ); 

我们必须异步加载Rust模块。调用 rust.hello_world() 会调用一个生成的封装函数,而这个函数又会调用 lib.rs 中定义的Rust函数 hello_world。

现在,运行 npm run serve 应该可以编译所有内容并启动开发服务器。我们没有定义HTML文件,因此页面上没有任何显示。你可能还必须手动转到 http://localhost:8080/index,因为http://localhost:8080只是列出文件而不执行任何代码。

打开空白页后,打开开发人员控制台。Hello World应该有一个日志条目。

好吧,对于一个简单的hello world来说,这是相当多的工作。但现在一切都到位了,我们可以轻松地扩展Rust代码,而不用担心这些。保存对 lib.rs 的修改后,你应该会自动看到重新编译和浏览器中的实时更新,就像JavaScript一样。

何时使用Rust

Rust不是JavaScript的一般替代品。它只能通过Wasm在浏览器中运行,这在很大程度上限制了它的作用。即使你可以用Rust替换几乎所有的JavaScript代码,如果你真的想的话,那是一个坏主意,而且不是Wasm的目的。例如,Rust并不适合与你网站的UI进行交互。

我认为Rust + Wasm是一个额外的选项,可以用来更有效地运行CPU重的工作负载。以较大的下载量为代价,Wasm避免了JavaScript代码面临的解析和编译开销。这一点,再加上编译器的强力优化,可能会带来更好的性能。这通常是公司为特定项目选择Rust的原因。选择Rust的另一个原因可能是语言偏好,但这是一个完全不同的讨论,我不会在这里讨论。

参考资料

[1]文章: https://www.sitepoint.com/quick-tip-multiple-versions-node-nvm/

[2]GitHub仓库: https://github.com/sitepoint-editors/rust-wasm-hello-world

[3]TOML: https://github.com/toml-lang/toml

[4]crates.io: https://crates.io/

[5]wasm-bindgen: https://crates.io/crates/wasm-bindgen

[6]web-sys: https://crates.io/crates/web-sys

[7]web-sys文档: https://rustwasm.github.io/wasm-bindgen/api/web_sys/console/index.html

[8]webpack experiments: https://webpack.js.org/configuration/experiments/

本文转载自微信公众号「前端全栈开发者」,可以通过以下二维码关注。转载本文请联系前端全栈开发者公众号。

 

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

针对JavaScript开发人员的Rust简介

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

针对JavaScript开发人员的Rust简介

亚马逊和微软都认可它是其系统中C / C ++的最佳替代品,但是Rust并不止于此。像Figma和Discord这样的公司现在也通过在客户端应用中使用Rust来引领潮流。

针对JavaScript开发人员的Rust简介是怎样的

这期内容当中小编将会给大家带来有关针对JavaScript开发人员的Rust简介是怎样的,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Rust是2010年起源于Mozilla Research的一种编程语
2023-06-15

专门针对开发人员,攻击者利用Rust获取操作系统信息

近日,研究人员在 Rust 编程语言的 crate 注册表中发现了一些恶意软件包,专门针对开发人员。

针对iOS开发人员的Xcode供应链攻击

一个名为XcodeSpy的恶意Xcode项目正在通过供应链攻击iOS开发人员,在开发人员的计算机上安装macOS后门。

面向嵌入式软件开发人员的 Docker 简介

在过去的几年里,Docker 席卷了软件行业。Docker 为嵌入式开发人员提供了一个“用于开发、发布和运行应用程序的开放平台”。docker提供的主要优势是,它可以通过在容器中构建环境来将应用程序与其运行的基础设施分开,然后可以在几乎任何

面向开发人员的 DevOps — 简介和版本控制

提高我们的 DevOps 技能可以帮助我们成为更好的开发人员、队友和管理者。学习 DevOps 原则和对 Git 的不同看法。
DevOps开发2024-11-30

针对Python开发人员的10个“疯狂”的项目构想

这些项目构想很有可能会让你对这门神奇的语言产生兴趣。最棒的是,你可以通过这些有趣但也具有挑战性的项目来增强你的 Python 编程技能。让我们来一一看下。

研究发现超 200 个针对 Azure 开发人员的恶意 NPM 包

JFrog 研究人员 Andrey Polkovnychenko 和 Shachar Menashe 在一份报告中指出,截至 3 月 21 日他们已观察到不少于 218 个恶意 NPM 包。据介绍,攻击人员使用的软件供应链攻击方法是 typ

恶意 NuGet 软件包利用 SeroXen RAT ,针对 .NET 开发人员

据了解,真实软件包迄今已获得近 79000 次下载,但恶意变种在 2023 年 10 月 6 日发布后人为虚假夸大了下载次数,让其下载量突破了 10万 次。

警惕!新形式的钓鱼软件专门针对 Python 开发人员

最近,一种新形式的钓鱼软件专门攻击 Python 开发人员。目前,这些软件包的下载量已高达 5,700 次。

Node.js 全局对象:JavaScript 开发人员的必备工具包

Node.js 全局对象提供了许多有用的功能,可以帮助 JavaScript 开发人员构建强大的服务器端应用程序。本文将介绍 Node.js 全局对象的一些常用属性和方法,并提供一些演示代码。
Node.js 全局对象:JavaScript 开发人员的必备工具包
2024-02-04

Android开发之针对联系人的封装

大家可能在做app的时候,或多或少需要使用联系人,而根据google提供的api,你需要编写大量的代码,例如首先需要查询数据库,涉及到数据库表和字段以及对应的SQL语句。 那么我们是否可以在我们的项目中添加联系人模块,这样能够更方便的使用手
2022-06-06

揭秘 Node.js 全局对象:JavaScript 开发人员的不二法门

Node.js 全局对象扮演着至关重要的角色,它提供了丰富的属性和方法,极大地便利了 JavaScript 开发人员的工作。本文将深入探讨 Node.js 全局对象,揭示其奥秘,并通过演示代码展示其强大功能。
揭秘 Node.js 全局对象:JavaScript 开发人员的不二法门
2024-02-04

浅析iOS开发人员转向JavaScript开发的原因

随着移动设备的普及和移动应用的流行,前端开发人员找到了一个新的机会来展示他们的技能。在人们的智能手机和平板电脑中,应用程序的强大功能为这些设备赋予了更大的功能和灵活性。对于iOS开发人员而言,使用JavaScript来开发应用程序已经成为一种流行的趋势。在此之前,iOS开发主要采用了两种语言来开发应用程序:Objective-C和Swift。这两种语言有自己的优势和不足,它们在
2023-05-14

苹果开发人员再次被盯,针对Xcode的供应链攻击再现

网络安全研究人员近期披露了一种新的攻击手法,攻击者利用植入后门的 Xcode 作为攻击媒介攻击苹果平台的开发人员,可以发现从供应链入手攻击开发人员和研究人员的状况已经愈演愈烈。

Python3+Django3开发简单的人员管理系统

1、使用PyCharm创建Django项目 记得安装mysqlclient (1)数据库配置 我们在项目的 settings.py 文件中找到 DATABASES 配置项,将其信息修改为: DATABASES = { "default": {
Python3+Django3开发简单的人员管理系统
2017-11-07

七个对 Web 开发人员有用的资源

在本文中,我们将深入探讨每位 Web 开发人员都应了解的 7 种宝贵资源。这些资源经过精心挑选,可帮助您最大限度地提高效率,最大限度地减少重复性任务,并专注于真正重要的事情。
Web开发工具2024-11-30

九个对Web开发人员有用的CSS工具

在这篇文章中, 介绍一些前端开发人员都可以使用的工具列表,让你的生活变得更轻松、更高效。在 CSS 属性中,过渡属性具有多种可能性,因此很难从头到尾记住所有属性。
前端CSS2024-11-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录