转自http://relistan.com/a-week-with-mozilla-rust/

A Week with Mozilla's Rust

I want another systems language in my tool belt. I want a language where I can be much more productive than in C: one in which I do not fear the correctness of my memory management, and don’t have to go through major gyrations to write concurrent code. But since I want a systems language that can effectively replace C, anything with enforced garbage collection like Go is out. Go is also not particularly friendly to interface to external libraries written in C. C++ has all of the pitfalls of C memory management and does not improve the concurrency situation at all. There are a few contenders still standing at that point, but I’ll look at one of them here.

Mozilla’s Rust might be the solution. Rust’s big wins are a modern object system, closures, a concurrency system designed for multi-core systems, and a memory model where the compiler can tell you if you’re doing something wrong or unsafe at compile time. Rust is also ABI compatible with C which makes tying libraries written in Rust into external code a minimal effort. Even less effort is required when tying C libs to Rust. If you want garbage collection, you can have it and you are fully in control of which memory is managed in this way. Wins all around.

I spent a week working with Rust to get a better understanding of what it can and can’t do, and what I might be able to use it for. What I found is a really appealing language with a lot of great thinking behind it. But it is heavily in flux at the moment, as its 0.7 release number indicates. I wrote some code in 0.6 just before the 0.7 release arrived. I then spent the better part of an evening migrating my couple of hundred lines of code. And the current pace of revisions is likely to continue for a few releases: more breaking changes are in the works for 0.8. However, all this churn does seem to represent advancement and refinement in the language and compiler so it’s not for nothing. I understand that a 1.0 release is slated for the latter part of the year.

As the community around any language is as important as the language, I wondered how Rust would fare. What I’ve found so far is a friendly group of very competent people who were perfectly happy to assist me on IRC when I fell afoul of the documentation and my ability to read the compiler code. The compiler is itself written mostly in Rust now. Mozilla already sits squarely at the center of a fairly robust community and it seems that Rust is benefitting from that strength. I have yet to see fewer than 200 people on the IRC channel, and /r/rust on Reddit is fairly active.

My summary on the state of things is that they are too much in flux for anything like production code at the moment. But I don’t think it will be that long before that situation is reversed. I expect major work will be happening in Rust by this time next year as the language settles down and major libraries can start to be written.

That’s how I see the state of all things Rust. But, I’d like to show some of the niceties of Rust so let’s take a look at some of my code. Full disclaimer: I don’t claim that any of this code is either correct or idiomatic Rust. It is solely my best effort. Feedback is of course welcome.

Some Code

You can take a look at the whole project on GitHub

My experiment was to wrap some of the hashing functions from OpenSSL and to implement HMAC in Rust natively. This seemed to be a low enough level exercise to test Rust’s chops as a systems programming language while also getting a sense of how it feels to write native Rust code. I found that I really like the language and that generally when I wanted to reach for something it was there. When it wasn’t, I had only to make a few adjustments to my thinking and there was a nice set of tools waiting at hand.

FFI

Linking C libraries to your Rust code is dead simple if you just need to access some C functions. You simply define the method sigantures with types that Rust can understand and give it a hint about linking the required shared library (if any). Here is the complete code for wrapping some C hashing methods with Rust’s Foreign Function Interface (FFI). Note that this is 0.7 code.

mod crypto {
use std::libc::c_uint;
#[link_args = "-lcrypto"]
extern {
fn SHA1(src: *u8, sz: c_uint, out: *u8) -> *u8;
fn MD5(src: *u8, sz: c_uint, out: *u8) -> *u8;
fn SHA224(src: *u8, sz: c_uint, out: *u8) -> *u8;
fn SHA256(src: *u8, sz: c_uint, out: *u8) -> *u8;
fn SHA384(src: *u8, sz: c_uint, out: *u8) -> *u8;
fn SHA512(src: *u8, sz: c_uint, out: *u8) -> *u8;
}
}

You can now access those methods as if they were written in Rust itself.

Things get more complicated if you need to pass data structures into the C code. But it’s not horrible due to the fact that Rust’s structs are interchangeable with C. You define your data structure in Rust and then pass it to the C functions just as you would natively. Other situations like allocating blocks of memory to pass in are catered to with the standard vec module.

Object System

The object system is modern and very nice to use. Objects are effectively structs with code associated with them. You define a struct and then, in a separate impl block, you write the code that will make up the class and instance methods. Here is one simple type I used for returning digests from hashing functions:

struct Digest { digest: ~[u8] }

impl Digest {
fn new(digest: ~[u8]) -> ~Digest { return ~Digest{ digest: digest } } fn hexdigest(&self) -> ~str {
let mut acc = ~"";
for self.digest.iter().advance |&byte| { acc = acc.append(fmt!("%02x", byte as uint)); }
acc
}
}

There is effectively one class method here and one instance method. Thehexdigest method requires that the first argument be a reference to an object of type Digest. Much like in Python, this is passed for you when the method is invoked on the object. But it is a signal to the compiler that this is an instance method not a class method.

Side note: If you’re wondering why I didn’t write something likeacc += fmt(!...) that is because in 0.7 += is currently removed for strobjects. This is slated to return in 0.8.

The new method on the other hand takes no &self argument. It is like a class method. One thing that is not obvious here, is that you can re-open classes at any time with a new impl block and add new code. This idiom is often used in Ruby and other dynamic languages when working with external libraries and I think this functionality will serve Rust well. It is rather unique for a compiled language.

Using the Digest object looks like this:

let digest = Digest::new(_some_binary_);
println(fmt!("%s", digest.hexdigest()));

Closures

We also see a closure in the code above. Coming from Ruby, these feel really nice in Rust as they are by appearances quite similar. I won’t get into a long explanation about iterators here (they are in flux), but the advance method takes a closure. We then modify the mutable acc variable on each iteration as the closure has this variable in scope. Nice.

Pattern Matching

Something not yet mentioned is the pattern matching system in Rust. This is similar to that in Erlang and other languages and lends some really flexible syntax to certain statements. A short example of pattern matching (albeit not the best example) from my project was this:

let computed_key = match key.len() {
_ if key.len() > self.block_size => self.zero_pad(self.hash(key).digest),
_ if key.len() < self.block_size => self.zero_pad(key),
_ => key
};

The match block does a pattern match on key.len() in this case. The following lines then define matches which might fit. The underscore is a universal match, and if you look at this carefully it appears that all lines will match. However, the if statements following the pattern are guards that must be true in order for the pattern to match.

This is a slight abuse of match, using it much more like a switchstatement. It keeps the code clean and compact though. And one of the nice things about pattern matching is that the compiler will analyze the block to the best of its ability and error if there is a case for which you have not supplied a pattern. Had we left the final _ => key off the pattern, this would not have compiled. More helpful validation at compile time to save us from errors at run time.

More to Come

I put up all the code on GitHub for review. I will not claim that this is correct or idiomatic Rust code, but it may serve to show off some of the things you can do in Rust. I will continue to contribute to the Rust community as it develops.

转 A Week with Mozilla's Rust的更多相关文章

  1. Rust语言

    Rust语言 https://doc.rust-lang.org/stable/book/ http://www.phperz.com/article/15/0717/141560.html Rust ...

  2. Rust语言——无虚拟机、无垃圾收集器、无运行时、无空指针/野指针/内存越界/缓冲区溢出/段错误、无数据竞争

    2006年,编程语言工程师Graydon Hoare利用业余时间启动了Rust语言项目.该项目充分借鉴了C/C++/Java/Python等语言的经验,试图在保持良好性能的同时,克服以往编程语言所存在 ...

  3. 5分钟APIG实战: 使用Rust语言快速构建API能力开放

    序言:Rust语言简介 参与过C/C++大型项目的同学可能都经历过因为Null Pointer.Memory Leak等问题“被” 加班了不知道多少个晚上.别沮丧,你不是一个人,Mozilla Fir ...

  4. [转帖]什么是 LLVM?Swift, Rust, Clang 等语言背后的支持

    要了解用于以编程方式生成机器原生代码的编译器框架是如何让新语言的推出以及对现有的语言进行增强比以往更加容易了. https://www.oschina.net/translate/what-is-ll ...

  5. 如何设计一门语言(八)——异步编程和CPS变换

    关于这个话题,其实在(六)里面已经讨论了一半了.学过Haskell的都知道,这个世界上很多东西都可以用monad和comonad来把一些复杂的代码给抽象成简单的.一看就懂的形式.他们的区别,就像用js ...

  6. Node.js的线程和进程

    http://www.admin10000.com/document/4196.html 前言 很多Node.js初学者都会有这样的疑惑,Node.js到底是单线程的还是多线程的?通过本章的学习,能够 ...

  7. Swift初步介绍

    Swift是本届WWDC大会苹果推出的一门新开发语言,开发者网站上已经放出了这门新语言的介绍.教程和手册,如果手里有一台iOS设备的话,通过苹果的iBooks应用,从它的官方书店里搜索Swift,可以 ...

  8. 2019 年软件开发人员必学的编程语言 Top 3

    AI 前线导读:这篇文章将探讨编程语言世界的现在和未来,这些语言让新一代软件开发者成为这个数字世界的关键参与者,他们让这个世界变得更健壮.连接更加紧密和更有意义.开发者要想在 2019 年脱颖而出,这 ...

  9. libuv之介绍

    本人是在研究linux下socket TCP/IP通讯时,用到了一些linux下的API,比如socket, connect, bind,listen, accept等等,简单写个点对点的通讯,直接用 ...

随机推荐

  1. HDU 4473 Exam 枚举

    原题转化为求a*b*c <=n中选出两个数组成有序对<a,b>的选法数. 令a<=b<=c.... 分情况讨论: (1)全部相等,即a = b = c. 选法有n^(1/ ...

  2. LVS的调度算法

    LVS的调度算法(Scheduling Method)一共有10种 一.静态方法:仅根据算法本身进行调度 1.rr(Round Robin):轮询 2.wrr(Werghted Round Robin ...

  3. 配置vim环境

    <1> 一般不建议更改/etc/vimrc这个文件,因为此文件更改对所有用户生效, 故一般只更改当前用户 即更改文件 vim ~/.vimrc (.表示隐藏文件) <2> 该文 ...

  4. 论文笔记之:Speed Up Tracking by Ignoring Features

    Speed Up Tracking by Ignoring Features CVPR 2014 Abstract:本文提出一种特征选择的算法,来实现用最"精简"的特征以进行目标跟 ...

  5. C#List转字符串,字符串转List,字符数组转Int数组

    List转字符串 [C#] 纯文本查看 复制代码 ? 01 02 List<string> List = new List<string>(); string strArray ...

  6. javascript中的闭包解析

    学习javaScript已经有一段时间了,在这段时间里,已经感受到了JavaScript的种种魅力,这是一门神奇的语言,同时也是一门正在逐步完善的语言,相信在大家的逐步修改中,这门语言会逐步的完善下去 ...

  7. LAMP平台搭建菜鸟入门级实验

    LAMP平台搭建(菜鸟入门级) mysql 安装: (1)二进制安装  二进制安装 ,执行解压配置即可.无须执行三布安装. (2)源码编译安装 安装准备工作: (1)查看系统配置:#uname -a/ ...

  8. 关于oracle修复控制文件与数据文件不一致的问题----

    本小菜鸟周末鼓捣数据库关于rman恢复与备份方面的实验,结果不知道哪根筋搭错了,手一哆嗦,做了不知道什么操作,就出现了数据库打不开的严重状态,只能开启到mount状态,但是切换到open状态时就会报错 ...

  9. java内存溢出分析(一)

    在项目中发现内存占用过高,且一直不会释放,top命令如下图显示 可以看到pid为17453的java进程占用27.1%内存,且长时间没有释放. 1.使用命令生成heap日志以供分析 sudo jmap ...

  10. HttpWebRequest.GetResponse 方法 转载

    GetResponse 方法返回包含来自 Internet 资源的响应的 WebResponse 对象. 实际返回的实例是 HttpWebResponse,并且能够转换为访问 HTTP 特定的属性的类 ...