我有以下代码:
extern crate futures; // 0.1.24
use futures::Future;
use std::io;
struct Context;
pub trait MyTrait {
fn receive(context: Context) -> Future<Item = (), Error = io::Error>;
}
pub struct MyStruct {
my_trait: MyTrait,
}
Run Code Online (Sandbox Code Playgroud)
当我尝试编译它时,我收到错误消息:
error[E0038]: the trait `MyTrait` cannot be made into an object
--> src/lib.rs:13:5
|
13 | my_trait: MyTrait,
| ^^^^^^^^^^^^^^^^^ the trait `MyTrait` cannot be made into an object
|
= note: method `receive` has no receiver
Run Code Online (Sandbox Code Playgroud)
我想我知道它为什么会发生,但我如何从结构中引用特征呢?可能吗?也许还有其他方法可以实现相同的行为?
我想编写一个函数来读取文件的内容,并在失败时引发错误。我想从 python 脚本调用这个函数,所以我在下面提到了一些 Python 以防它可能相关。
正如我在评论中尝试显示的那样,可能会发生更多的工作,从而引发其他类型的错误,因此,如果可能的话,我想使用通用错误(如果 Rust 中可以实现)(?)。如何返回错误,以便可以对其进行处理并将其包装在 python 错误中,如图所示do_work?不确定我导致以下错误的方法是否方向正确。
fn work_with_text() -> Result<(), dyn std::error::Error> {
let content = match std::fs::read_to_string("text.txt") {
Ok(t) => t,
Err(e) => return Err(e),
};
// do something with content that may cause another type of error (rusqlite error)
Ok(())
}
#[pyfunction]
fn do_work(_py: Python) -> PyResult<u32> {
match work_with_text() {
Ok(_) => (0),
Err(e) => {
let gil = Python::acquire_gil();
let py = gil.python();
let error_message = format!("Error happened {}", e.to_string()); …Run Code Online (Sandbox Code Playgroud) 我想在任务之间发送一个特征对象,但无法弄清楚它是否可能.它似乎可能不是,因为它们显然不符合这一Send特性.
以下代码演示了我正在尝试做的事情:
use std::{
sync::mpsc::{channel, Receiver, Sender},
thread,
};
trait Bar {
fn bar(&self);
}
struct Foo {
foo: i32,
}
impl Bar for Foo {
fn bar(&self) {
println!("foo: {}", self.foo);
}
}
fn main() {
let foo = Box::new(Foo { foo: 1 }) as Box<dyn Bar>;
let (tx, rx): (Sender<Box<dyn Bar>>, Receiver<Box<dyn Bar>>) = channel();
thread::spawn(move || {
tx.send(foo).unwrap();
});
let sent = rx.recv().unwrap();
sent.bar();
}
Run Code Online (Sandbox Code Playgroud)
此操作失败,并显示以下消息:
error[E0277]: `dyn Bar` cannot be sent between threads safely …Run Code Online (Sandbox Code Playgroud) 引用这本书(强调我的),
当使用特征时,用具体类型参数填充的泛型类型参数也是如此:具体类型成为实现该特征的类型的一部分。当通过使用特征对象而忘记类型时,就无法知道用什么类型填充泛型类型参数。
我无法理解其中的道理。对于具体示例,请考虑以下内容
pub trait Echoer {
fn echo<T>(&self, v: T) -> T;
}
pub struct Foo { }
impl Echoer for Foo {
fn echo<T>(&self, v: T) -> T {
println!("v = {}", v);
return v;
}
}
pub fn passthrough<T>(e: Box<dyn Echoer>, v: T) {
return e.echo(v);
}
fn main() {
let foo = Foo { };
passthrough(foo, 42);
}
Run Code Online (Sandbox Code Playgroud)
结果当然是报错
$ cargo run
Compiling gui v0.1.0 (/tmp/gui)
error[E0038]: the trait `Echoer` cannot be made into …Run Code Online (Sandbox Code Playgroud) 如果我有一个特质Foo,并且有一些实现者Bar,Baz.
impl Foo for Bar {
}
Run Code Online (Sandbox Code Playgroud)
impl Foo for Baz {
}
Run Code Online (Sandbox Code Playgroud)
但是假设我只使用其中一个作为特征对象,
let bar = Bar {..};
let foo: &dyn Foo = &bar;
Run Code Online (Sandbox Code Playgroud)
那么我的二进制文件仍然有两个 vtable 吗?这种行为在调试和发布版本之间是否会发生变化?
我不能在不使用闭包的情况下编译它.我试图让函数apply首先返回正确的闭包.
#![feature(conservative_impl_trait)]
#![allow(dead_code)]
fn accumulate<'a>(tuples: &[(&'a str, &Fn(i32) -> bool)], i: i32) {
// this works
let _ = tuples.iter().filter(|t| apply(second, i)(t));
// this doesn't
//let f = apply(second, i);
//let _ = tuples.iter().filter(f);
//this works as well
let f = |t: &&(_,_)| apply(second, i)(t);
let _ = tuples.iter().filter(f);
}
fn apply<A, B, C, F, G>(mut f: F, a: A) -> impl FnMut(B) -> C
where F: FnMut(B) -> G,
G: FnMut(A) -> C,
A: Clone
{
move …Run Code Online (Sandbox Code Playgroud) 在编写具有特征的代码时,您可以将特征置于特征界限中:
use std::fmt::Debug;
fn myfunction1<T: Debug>(v: Box<T>) {
println!("{:?}", v);
}
fn myfunction2<T: Debug>(v: &T) {
println!("{:?}", v);
}
fn main() {
myfunction1(Box::new(5));
myfunction2(&5);
}
Run Code Online (Sandbox Code Playgroud)
或直接使用Box或引用类型:
use std::fmt::Debug;
fn myfunction3(v: Box<Debug>) {
println!("{:?}", v);
}
fn myfunction4(v: &Debug) {
println!("{:?}", v);
}
fn main() {
myfunction3(Box::new(5));
myfunction4(&5);
}
Run Code Online (Sandbox Code Playgroud)
这些输出相同.那么区别是什么呢?
(这个问题的灵感来自另一个问题,这只是几个混合概念中的一个)
我最初在这里问过这个问题,但它被标记为重复,尽管在我看来它只重复了其中的一部分,所以我创建了一个更具体的问题:
考虑以下代码:
use std::rc::Rc;
trait MyTrait {
fn trait_func(&self);
}
struct MyStruct1;
impl MyStruct1 {
fn my_fn(&self) {
// do something
}
}
impl MyTrait for MyStruct1 {
fn trait_func(&self) {
// do something
}
}
fn my_trait_fn(t: Rc<dyn MyTrait>) {
t.trait_func();
}
fn main() {
let my_str: Rc<MyStruct1> = Rc::new(MyStruct1);
my_trait_fn(my_str.clone());
my_str.my_fn();
}
Run Code Online (Sandbox Code Playgroud)
这段代码工作正常。现在我想更改 的定义trait_func以接受 a &mut self,但它不会像Rc仅适用于不可变数据那样工作。我使用的解决方案是包装MyTrait成RefCell:
use std::cell::RefCell;
fn my_trait_fn(t: Rc<RefCell<Box<dyn MyTrait>>>) {
t.borrow_mut().trait_func();
}
fn …Run Code Online (Sandbox Code Playgroud) 我正在尝试克隆盒装特征的向量.自然地简单地派生Clone所有实现我的特征的结构是不够的,因为编译器在编译时不知道实现特征的所有结构都有Clone.
好的,所以我接着尝试使用Clonesupertrait,但这只会导致标题中的错误.我对解决方案感到茫然.
这是最小工作实现(或不工作,因为我无法克隆)
#![allow(dead_code, unused_macros)]
use std::fmt::Debug;
trait MusicElement: Debug + Clone {
fn duration(&self) -> f32;
}
#[derive(Debug, Clone)]
struct Note<'a> {
name: &'a str,
duration: f32,
}
impl<'a> MusicElement for Note<'a> {
fn duration(&self) -> f32 {
self.duration
}
}
#[derive(Debug, Clone)]
struct Pause {
duration: f32,
}
impl MusicElement for Pause {
fn duration(&self) -> f32 {
self.duration
}
}
#[derive(Debug, Clone)]
struct Sequence {
elements: Vec<Box<MusicElement>>,
}
impl MusicElement for …Run Code Online (Sandbox Code Playgroud) 首先,我不是问&mut和ref mut本身有什么区别.
我在问,因为我想:
let ref mut a = MyStruct
Run Code Online (Sandbox Code Playgroud)
是相同的
let a = &mut MyStruct
Run Code Online (Sandbox Code Playgroud)
考虑从函数返回特征对象.你可以退还一个Box<Trait>或一个&Trait.如果您希望对其方法进行可变访问,是否可以返回&mut Trait?
鉴于这个例子:
trait Hello {
fn hello(&mut self);
}
struct English;
struct Spanish;
impl Hello for English {
fn hello(&mut self) {
println!("Hello!");
}
}
impl Hello for Spanish {
fn hello(&mut self) {
println!("Hola!");
}
}
Run Code Online (Sandbox Code Playgroud)
该方法接收可变参考用于演示目的.
这不会编译:
fn make_hello<'a>() -> &'a mut Hello {
&mut English
}
Run Code Online (Sandbox Code Playgroud)
也不是这样
fn make_hello<'a>() -> &'a …Run Code Online (Sandbox Code Playgroud) rust ×10
trait-objects ×10
traits ×6
generics ×2
polymorphism ×2
clone ×1
closures ×1
mutable ×1
vtable ×1