【问题标题】:Trait is not implemented for the type `&A` when passing an array of pairs to a function将一对数组传递给函数时,没有为类型“&A”实现特征
【发布时间】:2016-03-15 16:23:55
【问题描述】:

我正在尝试编写函数set,它调用Rust LMDB library (docs),例如我是working off of。

我这辈子都无法让它发挥作用。这是我目前的尝试:

fn main() {
    let env = getenv("duperdb");
    let dbhandle = get_dbhandle("", &env);
    let txn = new_transaction(&env);
    let vec = vec![("foo", "another text"), ("bar", "and another")];
    set(&dbhandle, &env, &vec);

    let reader = env.get_reader().unwrap();
    let db = reader.bind(&dbhandle);
    let note = db.get::<&str>("foo").unwrap();

    println!("NOTE: {}", note);
}

其中set定义为:

pub fn set<A: ToMdbValue, B: ToMdbValue>(
    handle: &DbHandle,
    env: &Environment,
    pairs: &Vec<(&A, &B)>) -> () {

    let txn = new_transaction(&env);

    {
        let db = txn.bind(&handle);

        for &(id, note) in pairs.iter() {
            db.set(&id, &note).unwrap();
        }
    }

    match txn.commit() {
            Err(_) => panic!("Failed to commit!"),
            Ok(_) => (),
    }
}

这会吐出以下错误:

src/db/wrapper.rs:28:20: 28:23 error: the trait `lmdb::traits::ToMdbValue` is not implemented for the type `&A` [E0277]
src/db/wrapper.rs:28             db.set(&id, &note).unwrap();
                                        ^~~

我也试过db.set(id, note).unwrap();,但这次我得到了:

src/main.rs:13:5: 13:8 error: the trait `core::marker::Sized` is not implemented for the type `str` [E0277]
src/main.rs:13     set(&dbhandle, &env, &vec);
                   ^~~
src/main.rs:13:5: 13:8 help: run `rustc --explain E0277` to see a detailed explanation
src/main.rs:13:5: 13:8 note: `str` does not have a constant size known at compile-time
src/main.rs:13:5: 13:8 note: required by `dupernote::db::wrapper::set`
src/main.rs:13:5: 13:8 error: the trait `lmdb_rs::traits::ToMdbValue` is not implemented for the type `str` [E0277]
src/main.rs:13     set(&dbhandle, &env, &vec);
                   ^~~

我也尝试过类似的东西:

    for (id, note) in pairs.iter() {
        db.set(id, note).unwrap();
    }

但这也不起作用……我不完全明白为什么。 id 和 note 的类型不是 &amp;str,而不是 str?

【问题讨论】:

标签: pointers types rust borrow-checker lmdb


【解决方案1】:

这是您的问题的MCVE:

trait Example {}

impl Example for i32 {}

fn library_call<T>(value: T)
    where T: Example,
{}

fn user_call<T>(values: &[T])
    where T: Example,
{
    for i in values {
        library_call(i);
    }
}

fn main() {
    let values = vec![1, 2, 3];
    user_call(&values);
}

出现错误:

error: the trait `Example` is not implemented for the type `&T` [E0277]

library_call(i);
^~~~~~~~~~~~

错误消息完全正确 - Example未为 &amp;T 实现,它只保证为 T 实现。 &amp;T 和 T 是不同的类型。

相反,您需要指出对泛型类型的引用实现了您需要的特征:

fn user_call<T>(values: &[T])
    where for <'a> &'a T: Example,

然后你需要确保对具体类型的引用实际上实现了特征:

impl<'a> Example for &'a i32 {}

或更广泛的版本:

impl<'a, T> Example for &'a T
    where T: Example
{}

另见When should I not implement a trait for references to implementors of that trait?

【讨论】:

  • :( 我越来越困惑。所以我添加了impl&lt;'a, T&gt; ToMdbValue for &amp;'a T where T: ToMdbValue {},这会引发错误E0210。阅读 rustc 解释,我添加struct MyType&lt;T&gt;(T); 并像示例中一样调整。现在我得到“不是所有的特征项都实现了,缺少:to_mdb_value”......此时这是一个兔子洞。我没有简化这个例子,因为我不完全理解这个问题。
  • 另外:根据文档,ToMdbValue 是为 &amp;'a str 实现的。
  • @o_o_o-- 尝试更改您的 set 以具有像我的 user_call 这样的通用约束:where for &lt;'a&gt; &amp;'a A: ToMdbValue, for &lt;'a&gt; &amp;'a B: ToMdbValue,。
  • 这就是我所做的,它导致了这些错误。 pub fn set&lt;A&gt;(handle: &amp;DbHandle, env: &amp;Environment, pairs: &amp;Vec&lt;(&amp;A, &amp;A)&gt;) -&gt; () where for &lt;'a&gt; &amp;'a A: ToMdbValue {
  • @o_o_o-- 也可以试试pairs: &amp;[(A, B)](你确实想要两种不同的类型,对吧?)。从来没有真正需要&amp;Vec。
【解决方案2】:

给你一个错误的函数的定义(如果我没看错文档的话):

fn set(&self, key: &ToMdbValue, value: &ToMdbValue) -> MdbResult<()>

key 必须是对特征对象的引用。您正在尝试传递对实现 ToMdbValue 的泛型类型的引用。

https://doc.rust-lang.org/book/trait-objects.html

我无法验证,但这应该可以:

pub fn set(handle: &DbHandle, env: &Environment, pairs: &Vec<(&ToMdbValue, &ToMdbValue)>) -> () {

    let txn = new_transaction(&env);

    {
        let db = txn.bind(&handle);

        for &(id, note) in pairs.iter() {
            db.set(id, note).unwrap();
        }
    }

    match txn.commit() {
            Err(_) => panic!("Failed to commit!"),
            Ok(_) => (),
    }
}

其他事情:您可能想要使用盒装特征对象Box&lt;ToMdbValue&gt;。上面的链接解释了它。您应该传递 &amp;[YourType] 而不是 &amp;Vec&lt;[YourType]&gt;。

【讨论】:

  • 我得到不匹配的类型:“预期 &amp;collections::vec::Vec&lt;(&amp;lmdb_rs::traits::ToMdbValue, &amp;lmdb_rs::traits::ToMdbValue)&gt;,找到 &amp;collections::vec::Vec&lt;(&amp;str, &amp;str)&gt;”——我之前得到了这个,因此我认为我必须传递一个实现 ToMdbValue 的泛型 :(
  • @o_o_o--: 这意味着你也必须更改set 的调用站点,现在传递Vec&lt;(&amp;ToMdbValue, &amp;ToMdbValue)&gt; 而不是Vec&lt;(&amp;str, &amp;str)&gt;) => 更改正在冒泡。
【解决方案3】:

我设法让它工作。我不确定这个解决方案是否符合犹太教规,但我会发布它。

所以现在,在main() 中,我执行以下操作(以(int, string) kv 对为例):

let k = 1;
let val = "hello there";
let vec = vec![(&k, &val)];
set(&dbhandle, &env, &vec);

我不得不单独声明它们,因为vec![(&amp;1, &amp;"hello there")] 抛出了borrowed value does not live long enough 形式的错误。

set 现在看起来像这样:

pub fn set<A, B>(handle: &DbHandle, env: &Environment, pairs: &Vec<(&A, &B)>)
    -> ()
    where A: ToMdbValue,
          B: ToMdbValue {

    let txn = new_transaction(&env);

    {
        let db = txn.bind(&handle);

        for &(id, note) in pairs.iter() {
            db.set(id, note).unwrap();
        }
    }

    match txn.commit() {
            Err(_) => panic!("Failed to commit!"),
            Ok(_) => (),
    }
}

【讨论】:

    猜你喜欢
    • 2015-07-15
    • 2013-01-31
    • 2019-12-08
    • 2020-05-09
    • 2015-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-08
    相关资源
    最近更新 更多