cargo 使用本地库
前天又看了下Rust,乘热打铁,动手写点东西,写什么好呢?
这一年我遇到过最多的就是读配置了,从写了好几个东西都是需要从文件读参数或者写参数,甚至是原位替换! 从最开始用C写一点scalability都没有的到手写Hash再到接触C++后用容器,以及其间也用Ruby写过来应对需求。
所以打算写个库来自己用(我喜欢造轮子:blush:),在此之前我先用Rust把sudodev写一遍熟悉下先。
cargo new sdev --bin
新建一个项目,开始动手写。当写到读fstab
的时候,发现Rust没有C++里面的std::getline
,于是就自己实现一个,那么,问题就是我的Cargo.toml
里面的依赖是这样啊
[dependencies]
nix = "*"
连路径都没写,直接从GitHub下载的。。去https://doc.crates.io 找文档,在这儿的页面末尾看到
It’s gotten to the point that we probably want to split out a separate crate for others to use. To do this Cargo supports path dependencies which are typically sub-crates that live within one repository.
一个crate里面可以有许多个子crates,我现在大概就是这种情况。于是就试了。
这个项目的目录结构是这样的
tree .
.
├── Cargo.lock
├── Cargo.toml
└── src
├── main.rs
├── not
│ ├── Cargo.toml
│ └── not.rs
└── readline
├── Cargo.lock
├── Cargo.toml
└── readline.rs
一个crate里面包含了两个crate,这两个子crate都是用cargo new name
创建,这两个子crate的Cargo.toml
内容如下:
not/Cargo.toml
[lib]
name = "not"
path = "not.rs"
readline/Cargo.toml
[lib]
name = "readline"
path = "readline.rs"
其中lib
告诉cargo这是要编译成一个库,name
是指这个这个crate的名字path
是这个库的路径(file path)。在引入这个库时需要用extern
关键字来指明,我需要使用这两个库,那么我需要在src/main.rs
里面增加
extern crate readline;
extern crate not;
要使用这两个库中的东西,还需要
use readline::readline::Readlines; // crate::mod::trait;
use not::not::BitNot; // crate::mod::trait;
现在,库写好了,怎样让Cargo编译的时候找到这些库呢?Cargo的文档是这样写的
[dependencies]
hello_utils = { path = "hello_utils" }
它这里的目录结构大概是
hello_world
|
|___Cargo.toml
|___ main.rs
|___hello_utils
|
|___ Cargo.toml
|___ lib.rs
在项目的顶层目录中的Cargo.toml
中加入依赖。
按照这种写法,我顶层目录中的Cargo.toml
是这样
[dependencies]
nix = "*"
readline = { path = "src/readline" }
not = { path = "src/not" }
配置中的section字段不允许有重复,另外上面的"src/"
在这儿是必需的!去掉的话会出现”Could not find Cargo.toml
in xxx/xxx
“。
另外,还有一种写法(Stack Overflow上有人的回答),估计也是toml的语法。
[dependencies]
nix = "*"
[dependencies.readline]
path = "src/readline"
[dependencies.not]
path = "src/not"
附上第一次在实践中写的有用的mod:
not.rs
pub mod not {
trait BitAnd<T = Self> {
type Output;
fn bitand(&self, other: &T) -> T;
}
impl BitAnd for Vec<String> {
type Output = Vec<String>;
fn bitand(&self, other: &Vec<String>) -> Vec<String> {
let mut res: Vec<String> = Vec::new();
for i in self.iter() {
if other.contains(i) {
res.push(i.clone());
}
}
res
}
}
// actually: (a | b)~(a & b)
pub trait BitNot<T = Self> {
type Output;
fn bitnot(&self, other: &T) -> T;
}
impl BitNot for Vec<String> {
type Output = Vec<String>;
fn bitnot(&self, other: &Vec<String>) -> Vec<String> {
let mut res: Vec<String> = Vec::new();
let same: Vec<String> = self.bitand(other);
for i in self.iter() {
if !same.contains(i) {
res.push(i.clone());
}
}
for j in other.iter() {
if !same.contains(j) {
res.push(j.clone());
}
}
res.sort();
res
}
}
}
readline.rs
pub mod readline {
use std::fs::File;
use std::io::Read;
pub trait Readlines {
fn readlines(mut self) -> Vec<String>;
}
impl Readlines for File {
fn readlines(mut self) -> Vec<String> {
let mut content = String::new();
match self.read_to_string(&mut content) {
Ok(_) => {},
Err(e) => panic!(e)
}
let res = content.lines()
.map(move |x: &str| x.to_string())
.collect();
res
}
}
}