首頁>Club>
8
回覆列表
  • 1 # 使用者6694339975785

    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);

  • 中秋節和大豐收的關聯?
  • 民用汽車車架號是不是都是17位,有例外嗎?