2016-05-15 15 views
0

前言:我相當確定這應該是一件容易理解的事情,但我沒有任何運氣。我實際上一直在與貨運經理奮鬥,我一直希望它像C中的簡單include聲明,但它當然沒有那麼簡單。如果您對如何更好地構建此項目有所建議,請分享。使用Cargo在頂部製作較低等級的包裝箱

可以說,我有一個圖書館在魯斯與貨物管理。箱子被稱爲point,目錄看起來像這樣。

point/ 
├── Cargo.lock 
├── Cargo.toml 
├── src 
   └── lib.rs 

該箱子沒有依賴性。

現在,我已經建立了另一個庫,將使用這個point箱。這個庫被稱爲sat這個庫看起來是這樣的:

sat/ 
├── Cargo.lock 
├── Cargo.toml 
├── src 
   ├── circle.rs 
   ├── lib.rs 
   ├── point/ 
   └── polygon.rs 

注意point/是上面提到的點目錄。我之所以包括point作爲一個單獨的庫,而不是作爲內sat一個模塊,就是circlepolygon模塊都依賴於point(我不能想出一個辦法讓pointsat作爲一個模塊工作不重複代碼,這與問題並不真正相關,但與慣用的Rust庫結構相關,所以請隨時對更好的方式進行評論)。

這裏是Cargo.toml文件sat/

$ cat sat/Cargo.toml 
[package] 
name = "sat" 
version = "0.1.0" 

[dependencies] 
point = { path = "src/point" } 

現在,這一切都很好。但是,讓我們說我想創建一個使用sat作爲外部箱子的應用程序。 如何在此應用程序中訪問point庫,而無需包含point庫本身?

下面是一個示例,point庫中有一個名爲Point的結構體。 sat庫中有一個名爲Circle的結構體。比方說,我的示例源代碼如下所示:

$ cat src/main.rs 

extern crate sat; 

// I don't want to have to include the point crate because it is already 
// included in sat 
// extern crate point; 

fn main() { 

    // declare a polygon 
    // structure is: crate::module::struct::staticFunction 
    let polygon = sat::polygon::Polygon::new(<parameters>); 

    // I cannot declare a Point, because point is not a module in sat 
    // this errors out. 
    // However, this is the sort of thing that I would like to do. 
    let point = sat::point::Point::new(<parameters>); 

} 

回答

2

我不希望有包括point,因爲它已經包含在sat

(重點煤礦)

這並不意味着什麼。完全有可能(和所需的功能)您使用的包的版本可以是依賴項正在使用的包的不同版本。這允許您使用新版本的功能,而依賴項尚未更新(反之亦然)。這可以防止一個特定類型的「依賴地獄」。

不幸的是,它引入了另一一種依賴地獄的地方箱A的公共接口公開從箱B中的類型(1版),我們正在嘗試使用板條箱上貼了與箱子B(第2版)的公共接口。這會產生一系列令人困惑的錯誤,如「預計Foo,發現Foo」。這些消息是actively worked on

要實現的關鍵是通過將外部類型放入公共API中,您的公共API現在受外部類型的影響。這意味着當外部箱子碰撞版本時,您需要碰撞版本以保持語義版本控制!

這後一種情況是你正試圖選擇進入。

你有兩個選擇:

  1. Re-export the types you need
  2. 人們需要使用相同箱子和相同版本的文檔。

第一個看起來是這樣的:

點/ src目錄/ lib.rs

pub struct Point(pub u8, pub u8); 

SAT/SRC/lib.rs

extern crate point; 

pub use point::Point; 

pub struct Circle(pub point::Point); 

app/src/main.rs

extern crate sat; 

use sat::{Point, Circle}; 

fn main() { 
    let p = Point(0, 0); 
    let c = Circle(p); 
} 

這可能是最接近你正在尋找。否則,您需要明確將相關箱子添加到satapp。這並不是聞所未聞的,大多數與hyper一起玩的箱子都做同樣的事情。


我之所以包括點作爲一個單獨的庫,而不是作爲內飽和的模塊,是,無論是circlepolygon模塊取決於point。我無法想出一種方法來讓point作爲sat中的模塊工作,而無需重複代碼。

你應該弄清楚。包裝箱是巨大的,當你有一塊可重用的代碼你當然應該使用它們,但它們不是重用代碼的唯一方式

pub mod point { 
    pub struct Point(pub u8, pub u8); 
} 

pub mod square { 
    use point::Point; 

    pub struct Square(pub Point, pub Point); 
} 

pub mod circle { 
    use point::Point; 

    pub struct Circle(pub Point); 
} 

fn main() { 
    let c = circle::Circle(point::Point(0, 0)); 
    let s = square::Square(point::Point(0, 0), point::Point(1, 1)); 
}