gpt4 book ai didi

rust - 我可以声明给定特征的实现不应该是 Sized 吗?

转载 作者:行者123 更新时间:2023-11-29 08:07:34 26 4
gpt4 key购买 nike

我定义了一个特征 Foo,为 [u32] 实现了这个特征,并写了一个函数 bar 以这个特征作为参数( playground ):

trait Foo {
fn foo(&self) -> u32;
}

impl Foo for [u32] {
fn foo(&self) -> u32 {
self[0]
}
}

fn bar<T>(f: &T) -> u32
where
T: Foo,
{
f.foo() + 1
}

fn main() {
let f: &[u32] = &[42];
bar(f);
}

这不会编译,因为 bar 隐式期望其参数为 Sized:

error[E0277]: the trait bound `[u32]: std::marker::Sized` is not satisfied
--> src/main.rs:20:5
|
20 | bar(f);
| ^^^ `[u32]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u32]`
note: required by `bar`
--> src/main.rs:11:1
|
11 | / fn bar<T>(f: &T) -> u32
12 | | where
13 | | T: Foo,
14 | | {
15 | | f.foo() + 1
16 | | }
| |_^

我可以用 T: Foo + ?Sized 修复它,但是我必须为每个函数做这个,期待 Foo ,这是一个痛苦...

我可以一劳永逸地声明 Foo 的实现不应该是 Sized 吗?我在第 1 行尝试了 trait Foo: ?Sized,但编译器对此有提示。

这道题和Trait implementing Sized不一样。在那个问题中,Foo 参数被移动了,所以编译器想在编译时知道它的大小是正常的。在我的例子中,参数是一个引用,所以它不需要调整大小——但编译器仍然隐含地假定它是,除非明确告知(使用 + ?Sized).对于这个特定的特征,我想改变的是这个隐含的假设。

最佳答案

为什么编译器会提示 trait Foo: ?Sized

When you say that every Foo is Sized, you're kind of hiding the truth to yourself. Yes, every Foo is Sized but actually every type has a given size at some point. The real important information is that you're not saying how much this size is.

在这种情况下,您需要一个大小合适的[u32]:

error[E0277]: the trait bound `[u32]: std::marker::Sized` is not satisfied
|
| impl Foo for [u32] {
| ^^^ `[u32]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u32]`

更多信息请咨询this answerTrait implementing Sized .

为什么 T 不能取消大小,因为我们只有一个引用?

让我再次引用 this answer来自 Why does a reference to a trait in a generic function have to implement Sized?

By default, all generic types on functions implicitly have the Sized bound, regardless of how they are used. You need to explicitly opt-out of that requirement using ?Sized

这将解决您的问题:

fn bar<T>(f: &T) -> u32
where
T: Foo + ?Sized,
{
f.foo() + 1
}

Playground

也可以为 &[u32] 实现 Foo:

impl<'a> Foo for &'a [u32] {
fn foo(&self) -> u32 {
self[0]
}
}

fn bar<T>(f: T) -> u32
where
T: Foo,
{
f.foo() + 1
}

Playground

在这种特殊情况下,您甚至可以将您的实现概括为 Foo,它可以在 Vec 和数组以及对这些类型的引用上工作:

impl<T: AsRef<[u32]>> Foo for T {
fn foo(&self) -> u32 {
self.as_ref()[0]
}
}

有了新的impl Trait语法,bar 可以在最后两种情况下缩短为

fn bar(f: impl Foo) -> u32 {
f.foo() + 1
}

Playground

关于rust - 我可以声明给定特征的实现不应该是 Sized 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50483245/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com