我正在阅读一本 Rust 书,但我对这个例子感到困惑:
use std::fmt::Display;
fn main() {
test("hello");
test2("hello")
}
fn test(s: &dyn Display) {
println!("{}", s);
}
fn test2(s: &str) {
println!("{}", s);
}
Run Code Online (Sandbox Code Playgroud)
&'static str作为特征对象传递失败:
use std::fmt::Display;
fn main() {
test("hello");
test2("hello")
}
fn test(s: &dyn Display) {
println!("{}", s);
}
fn test2(s: &str) {
println!("{}", s);
}
Run Code Online (Sandbox Code Playgroud)
为什么这会失败而第二次调用有效?
我理解的规则,当一个特征可以做成一个特征对象,但我不明白为什么这些规则的存在。
例如:
trait Resource {
const RESOURCE_ID: u64;
}
trait ResourceStatic {
fn static_id() -> u64;
}
trait ResourceInstance {
fn resource_id(&self) -> u64;
}
struct MyResource {}
impl Resource for MyResource {
const RESOURCE_ID: u64 = 123;
}
impl ResourceStatic for MyResource {
fn static_id() -> u64 {
123
}
}
impl ResourceInstance for MyResource {
fn resource_id(&self) -> u64 {
123
}
}
Run Code Online (Sandbox Code Playgroud)
在我看来,这三个特征基本上都封装了相同的功能。那么为什么这些是不允许的:
let _: Box<dyn Resource> = Box::new(MyResource{});
let _: Box<dyn ResourceStatic> …Run Code Online (Sandbox Code Playgroud) 任何人都可以通过以下代码告诉问题是什么?编译器抱怨生命周期,但错误消息绝对没有意义.我已经尝试了我能想到的一切,但似乎没有任何帮助.
use std::borrow::BorrowMut;
trait Trait<'a> {
fn accept(&mut self, &'a u8);
}
struct Impl<'a>{
myref: Option<&'a u8>,
}
impl<'a> Trait<'a> for Impl<'a> {
fn accept(&mut self, inp: &'a u8) { self.myref = Some(inp); }
}
fn new<'a>() -> Box<Trait<'a> + 'a> {
Box::new(Impl{myref: None})
}
fn user<'a>(obj: &mut Trait<'a>) {}
fn parent<'a>(x: &'a u8) {
let mut pool = new();
user(pool.borrow_mut());
}
Run Code Online (Sandbox Code Playgroud)
编译器错误是
error: `pool` does not live long enough
--> src/wtf.rs:22:10
|
22 | user(pool.borrow_mut());
| ^^^^ does not …Run Code Online (Sandbox Code Playgroud) 我想要一个拥有的 Rust 特征对象列表。我可以实现它,Vec<Box<dyn Trait>>但是它会为每个特征对象在堆上分配空间。我更喜欢的是一种CompactList<dyn Trait>具有如下内存表示的类型:
[vtable1, size1, data1, vtable2, size2, data2, vtable3, size3, data3]
Run Code Online (Sandbox Code Playgroud)
size*是相应data*.
有了这个,我可以创建一个Iterator<Item = &dyn Trait>. 我唯一需要的操作CompactList<T>是push()和iter()。
我一直在尝试查找有关 Rust 如何在涉及模块边界的情况下解决特征包实现的文档,但没有找到与之直接相关的内容。
让我们考虑一个包含两个相似但略有不同的代码片段的示例:
第一个代码片段编译得很好,但会遭受无限的运行时递归。ClonableIterator发生这种情况是因为for 的全面实现T: Iterator+Clone与 which is 相匹配Box<dyn ClonableIterator<'a>>,这要归功于我们手动实现Clone和nowBox的全面实现。IteratorIterator+Clone
//the trait itself, with the indirection to call box_clone on the base type
trait ClonableIterator<'a>: Iterator<Item = &'a u32> + 'a {
fn box_clone(&self) -> Box<dyn ClonableIterator<'a>>;
}
//The blanket implementation of the trait for all clonable iterators
impl<'a, T: Iterator<Item = &'a u32> + Clone + 'a> ClonableIterator<'a> for T {
fn box_clone(&self) -> Box<dyn ClonableIterator<'a>> …Run Code Online (Sandbox Code Playgroud) 我正在研究一些 API 概念,并注意到 Rust 的 Iterator 特性中有一些特殊之处。
我有以下特征定义:
trait Observable {
type Item;
fn subscribe<F>(self, f: F) -> bool
where
Self: Sized,
F: FnMut(Self::Item) + 'static;
}
Run Code Online (Sandbox Code Playgroud)
然后我继续编写以下测试:
#[test]
#[should_panic]
fn trait_obj() {
let mut v: Vec<Box<dyn Iterator<Item = ()>>> = vec![];
let mut v2: Vec<Box<dyn Observable<Item = Ref<u8>>>> = vec![];
v.remove(0).for_each(|_| {});
v2.remove(0).subscribe(|_| {});
}
Run Code Online (Sandbox Code Playgroud)
正如人们所期望的那样,上述测试无法编译;subscribe()按值获取 self,并且对 具有Sized约束Self,因此不是对象安全的。但是,如果我注释掉该...subscribe行,它就会编译!
对我来说奇怪的是,Iterator::for_each()有相同的限制。为什么允许这样做Iterator而不是允许这样做Observable?这是一个实验性的功能吗?
Iterator::for_each这是供参考的函数签名:
// Iterator::for_each
fn for_each<F>(self, …Run Code Online (Sandbox Code Playgroud) 我有以下代码:
trait Bar {
fn baz(&self, arg: impl AsRef<str>)
where
Self: Sized;
}
struct Foo;
impl Bar for Foo {
fn baz(&self, arg: impl AsRef<str>) {}
}
fn main() {
let boxed: Box<dyn Bar> = Box::new(Foo);
boxed.baz();
}
Run Code Online (Sandbox Code Playgroud)
这导致此错误:
error: the `baz` method cannot be invoked on a trait object
--> src/main.rs:15:11
|
15 | boxed.baz();
| ^^^
Run Code Online (Sandbox Code Playgroud)
为什么这是不可能的?当我删除Self: Sized绑定时它可以工作,但是我不能使用泛型来使调用者更舒适地使用该函数。
这不是为什么 trait 中的泛型方法需要调整 trait 对象的大小?这问为什么你不能baz从特征对象调用。我不是问为什么需要绑定;这已经讨论过了。
在下面的代码中,不可能从对实现相同特征的动态大小类型的引用中获得对特征对象的引用。为什么会这样呢?究竟是什么区别&dyn Trait和&(?Sized + Trait)我是否可以使用这两种调用方法特质?
实现的类型FooTraitContainerTrait可能例如具有type Contained = dyn FooTrait或type Contained = T在哪里T实现的具体类型FooTrait。在这两种情况下,都很难获得&dyn FooTrait。我想不出另一种情况,这是行不通的。为什么在通用情况下这不可能FooTraitContainerTrait?
trait FooTrait {
fn foo(&self) -> f64;
}
///
trait FooTraitContainerTrait {
type Contained: ?Sized + FooTrait;
fn get_ref(&self) -> &Self::Contained;
}
///
fn foo_dyn(dyn_some_foo: &dyn FooTrait) -> f64 {
dyn_some_foo.foo()
}
fn foo_generic<T: ?Sized + FooTrait>(some_foo: &T) -> f64 {
some_foo.foo()
}
///
fn foo_on_container<C: FooTraitContainerTrait>(containing_a_foo: &C) -> …Run Code Online (Sandbox Code Playgroud) 通常的assert_eq!宏要求在结构中实现 PartialEq - 我有一个特征对象向量 ,Vec<Box<dyn Element>>其中 Element 是需要调试的特征,pub trait Element: std::fmt::Debug。我不能类似地要求,PartialEq因为它需要 Self 作为类型参数,编译器无法将其制作成特征对象。
我见过的解决方案涉及在特征定义中要求一个 eq 关联函数,这对我来说没有吸引力,因为这只是调试代码,而且我认为包含一个无用的方法不会有什么好处并且在构建之外添加特征的 API 可能会造成混淆cargo test。
是否有任何其他(可能不安全)的方法来比较两个特征对象?
我正在尝试在 Rust 中实现一个责任链:
use std::error::Error;
struct Query {
query: String,
}
struct Response {
response: u64,
}
trait Responsability {
fn take(&self, iterator: std::slice::Iter<Box<dyn Responsability>>, query: Query) -> Result<Response, Box<dyn Error>>;
}
struct ResponsabilityChain<T: Responsability> {
responsabilities: Vec<Box<T>>,
}
impl<T: Responsability> ResponsabilityChain<T>
where
T: Responsability,
{
pub fn new(responsabilities: Vec<T>) -> Self {
let responsabilities = responsabilities.into_iter()
.map(|elt| Box::new(elt))
.collect();
Self { responsabilities }
}
pub fn launch(&self, query: Query) -> Result<Response, Box<dyn Error>> {
let iterator = self.responsabilities.iter(); …Run Code Online (Sandbox Code Playgroud)