rust 之美,参数的多种形式

235 阅读1分钟

我们都知道 rust 是一种静态类型的语言,意味着它的参数类型必须的固定的,有些时候,我们可能会认为这是一个负担,例如下面的代码:

use aliyun_oss_client::Query;
let query = Query::new();
let response = client.get_object_list(query).await;
println!("objects list: {:?}", response);

来源 aliyun_oss_client - Rust (docs.rs)

因为 Query 里面包含了一个 HashMap,里面需要传递多组参数,例如:

use aliyun_oss_client::Query;
let mut query = Query::new();
query.insert("max-keys", "5");
query.insert("prefix", "babel");
let result = client.get_bucket_info().unwrap().get_object_list(query).unwrap();

来源 aliyun_oss_client::blocking - Rust (docs.rs)

对于第二个例子,我们还是可以接受的,在当前作用域里导入 Query 是必须要的,因为确实需要传递参数,所以说,看到第一个例子的时候,我们想当然的会认为,代码比较丑,rust好丑... 但是这是可以优化的,

我们可以更改函数的签名:

// before
pub async fn get_object_list(self, query: Query) -> OssResult<ObjectList> {
    ...
}

// now
pub async fn get_object_list<Q: Into<Query>>(self, query: Q) -> OssResult<ObjectList> {
    let query = query.into();
    ...
}

将参数 query 的类型改为可转换为 Query 类型的类型,然后在 Query 类型定义的地方,加一些 Form<T> 语句:

impl<K, V> From<Vec<(K, V)>> for Query
where
    K: Into<QueryKey>,
    V: Into<QueryValue>,
{
    fn from(vec: Vec<(K, V)>) -> Self {
        let mut query = Query::with_capacity(vec.len());

        for (key, val) in vec {
            query.insert(key, val);
        }

        query
    }
}

impl From<[(); 0]> for Query {
    /// 空数组转换成 Query
    fn from(_: [(); 0]) -> Self {
        Self::with_capacity(0)
    }
}

来源 oss-rs/types.rs at master · tu6ge/oss-rs (github.com)

这样,我们就可以像这样调用 get_object_list 方法了:

let response = client.get_object_list([]);
println!("objects list: {:?}", response);
let response = client.get_object_list(vec![("max-keys", "5"), ("prefix", "babel")]);
println!("objects list: {:?}", response);

然后我们就可以把丑陋的 use 语句扔掉了:

use aliyun_oss_client::Query;