rust物资刷新机制_你在开发过程中都遇到过 Rust 的哪些坑?

F001 已经提到unsafe和借用所有权天生带来的问题。除此之外目前还遇到另外几个让人不爽的地方,大部分已有RFC提出解决方案,但前途不乐观。

1. Rust没有subtype, enum 作为首选类型建模工具又没有实现Dependent Type,最后要enum套struct,比较丑陋。

摘自rustc源码

enum TypeStructure {

Bool, // bool

Reference(Region, Mutability, Type), // &'x T, &'x mut T

Struct(DefId, &'tcx Substs), // Foo<..>

Enum(DefId, &'tcx Substs), // Foo<..>

BareFn(&'tcx BareFnData), // fn(..)

...

}

vs C++

typedef TypeStructure *Ty;

class TypeStructure { .. };

class Bool : public TypeStructure { .. };

class Reference : public TypeStructure { .. };

class Struct : public TypeStructure { .. };

class Enum : public TypeStructure { .. };

class BareFn : public TypeStructure { .. };

2. 常数不能作为泛型参数。所以当结构包含不定长数组时,要将这个数组类型作为一个泛型参数,或传入数组引用,破坏了封装。

let mut vector: ArrayDeque = ArrayDeque::new();

vs

let mut vector: ArrayDeque<8> = ArrayDeque::new();

3. 不能栈上分配不定长内存。Rust中涉及闭包、trait object、环形引用的部分强制应用堆分配。在部分实时系统里不能用堆时就比较痛苦了。

4. 错误处理上偷师Haskell用Option又没学完,既没有monad 也没有 do notation。

这里举future的例子,option和result同理

Rust的Future大概是这样的。

fn main() {

let mut core = Core::new().unwrap();

let addr = "www.rust-lang.org:443".to_socket_addrs().unwrap().next().unwrap();

let socket = TcpStream::connect(&addr, &core.handle());

let cx = TlsConnector::builder().unwrap().build().unwrap();

let response = socket.and_then(|socket| {

cx.connect_async("www.rust-lang.org", socket).map_err(|e| {

io::Error::new(io::ErrorKind::Other, e)

})

}).and_then(|socket| {

tokio_core::io::write_all(socket, "\

GET / HTTP/1.0\r\n\

Host: www.rust-lang.org\r\n\

\r\n\

".as_bytes())

}).and_then(|(socket, _)| {

tokio_core::io::read_to_end(socket, Vec::new())

});

let (_, data) = core.run(response).unwrap();

}

别人家Scala的Future。

val usdQuote = Future { connection.getCurrentValue(USD) }

val chfQuote = Future { connection.getCurrentValue(CHF) }

val purchase = for {

usd

chf

if isProfitable(usd, chf)

} yield connection.buy(amount, chf)

purchase onSuccess {

case _ => println("Purchased " + amount + " CHF")

}

5. 不支持闭包参数占位符,也没有部分应用函数。combinator写起来丑陋不说,还比较容易混淆。比如官方文档说,

let letter_count = ['apple', 'banana'].iter().map(|str| { str.len() }).sum();

可以改写为

let letter_count = ['apple', 'banana'].iter().map(str::len).sum();

但当你豁然贯通之际想要重写下面这段代码的时候

let at_least_10: Vec<_> = [8, 9, 10, 11].iter().map(|x| { cmp::min(x, 10) }).collect();

发现Rust其实并没有部分应用函数。。。

let at_least_10: Vec<_> = [8, 9, 10, 11].iter().map(cmp::min(_, 10)).collect(); // 不能编译

再看看隔壁scala的

val at_least_10 = List(8, 9, 10, 11).map(_ min 10).reduceLeft(_ + _);

6. Trait 没有字段。这个见仁见智,trait默认实现用到结构的字段时,目前的标准写法是,trait定义一个 get_xxx()方法给结构实现,不是那么的高效。我觉得这个feature还是比较重要的,不知为何不在1.0前加入。,core team 早已有人提出, 但也是一直被推迟。

7. 最后是一个生命周期设计上的问题——生命周期过早开始和过早结束,在3年前被核心成员发现并提出解决方案,但一直推迟到1.0发布直到今天还没解决。

比方说,下面这段不能编译

let vec = vec![...];

vec.remove(vec.len() - 1); // vec已被借用

原因是第二句被展开为

Vec::remove(&mut vec, vec.len() - 1); // 第一个参数传递可变借用,第二个参数时就不能再借出了

一定要写成

let vec = vec![...];

let len = vec.len();

vec.remove(len - 1);

这当然有更好的写法,比如pop(),这样写只是为了表现生命周期的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值