【问题标题】:Why is ?Sized required to pass a reference to a generic type parameter?为什么需要 ?Sized 来传递对泛型类型参数的引用?
【发布时间】:2019-08-05 20:20:30
【问题描述】:

当我在 Rust 操场上运行以下代码时...

fn take_part_1<'a>(s: &'a str) -> &'a str {
    s.split(':').next().unwrap()
}

fn take_part_2<'a, T: 'a + AsRef<str>>(s: &'a T) -> &'a str {
    let b = s.as_ref().split(':').next().unwrap();
    b
}

fn main() {
    println!("{}", take_part_1("a:b"));
    println!("{}", take_part_2("a:b"));
}

...编译器返回一个没有意义的错误:

12 |     println!("{}", take_part_2("a:b"));
   |                    ^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `str`

我可以通过添加?Sized 来修复它,如下所示:

fn take_part_2<'a, T: 'a + AsRef<str> + ?Sized>(s: &'a T) -> &'a str {

为什么需要这个?Sized(以及为什么编译器将错误指向函数调用)?它有什么作用?我不应该能够将引用传递给未调整大小的对象并让它正常工作吗?

让我感到困惑的是,非泛型实现按您的预期工作,对 ?Sized 没有要求(即使编译器指出 str 不是 Sized!)

【问题讨论】:

  • 操场上的最小示例:Link

标签: generics reference rust dynamic-sizing


【解决方案1】:

大多数使用类型参数的地方,Rust 会隐式插入一个额外的Sized 绑定。那是因为这是最常见的情况 - 如果它的行为不是那样,那么您将不得不自己编写边界到处,它会变得重复和嘈杂。

例如,您的take_part 函数完全等价于:

fn take_part_2<'a, T: 'a + AsRef<str> + Sized>(s: &'a T) -> &'a str {
    let b = s.as_ref().split(':').next().unwrap();
    b
}

但是,您的函数的实现不需要TSized,因为它只通过引用使用它。添加: ?Sized 有效地删除了隐式绑定,向类型检查器传达不需要知道T 的大小,因此您的函数尽可能通用。在这种情况下,使其更通用允许使用 T 作为动态大小的类型 str 调用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-05
    • 2019-02-27
    • 1970-01-01
    相关资源
    最近更新 更多