为什么 String 不实现 From<&String>? [英] Why doesn't String implement From<&String>?

查看:21
本文介绍了为什么 String 不实现 From<&String>?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

我知道在 Rust 中人们更喜欢 &str 而不是 &String.但在某些情况下,我们只获得了 &String.

I know that in Rust people prefer &str rather than &String. But in some case we were only given &String.

一个例子是当你调用 std::iter::Iterator::peekable 时.返回值是一个 Peekable 对象,它将原始迭代器包装到其中并为您提供一个额外的方法 peek.

One example is when you call std::iter::Iterator::peekable. The return value is a Peekable<I> object that wraps the original iterator into it and gives you one extra method peek.

这里的重点是 peek 只给你一个对迭代器项的引用.因此,如果您有一个包含 String 的迭代器,则在这种情况下您只有 &String.当然,您可以轻松地使用 as_str 来获取 &str 但在我将在下面展示的代码中,它等效于对 clone.

The point here is that peek only gives you a reference to the iterator item. So if you have an iterator that contains Strings, you only have &String in this case. Of cause, you can easily use as_str to get a &str but in the code I will show below it is equivalent to a call to clone.

问题

此代码

#[derive(Debug)]
struct MyStruct(String);

impl MyStruct {
    fn new<T>(t: T) -> MyStruct
    where
        T: Into<String>,
    {
        MyStruct(t.into())
    }
}

fn main() {
    let s: String = "Hello world!".into();
    let st: MyStruct = MyStruct::new(&s);
    println!("{:?}", st);
}

不能编译,因为 String 没有实现 From<&String>.这不直观.

doesn't compile because String doesn't implement From<&String>. This is not intuitive.

为什么这不起作用?是标准库缺少一个特性还是有其他原因阻止标准库实现它?

Why does this not work? Is it just a missing feature of the standard library or there are some other reasons that prevent the standard library from implementing it?

在实际代码中,我只有一个对 String 的引用,我知道要让它工作我只需要调用 clone 代替,但我想知道为什么.

In the real code, I only have a reference to a String and I know to make it work I only need to call clone instead, but I want to know why.

推荐答案

为了解决您的问题,可以想象在标准库中添加一个新的泛型实现:

To solve your problem, one could imagine adding a new generic impl to the standard library:

impl<'a, T: Clone> From<&'a T> for T { ... }

或者让它更通用:

impl<B, O> From<B> for O where B: ToOwned<Owned=O> { ... }

<小时>

但是,这样做有两个问题:


However, there are two problems with doing that:

  1. 特化:允许重叠 trait-impls 的特化特性仍然不稳定.事实证明,以合理的方式设计专业化比更难预期(主要是由于生命周期).

  1. Specialization: the specialization feature that allows to overlapping trait-impls is still unstable. It turns out that designing specialization in a sound way is way more difficult than expected (mostly due to lifetimes).

如果它不是稳定的,Rust 开发人员会非常小心,不要在标准库的公共 API 的某处公开该功能.这并不意味着它在 std 中根本不使用!一个著名的例子是 str 的专用 ToString impl.它在在这个 PR 中被引入.正如您在 PR 的讨论中所读到的,他们只是接受了它,因为它没有改变 API(to_string() 已经为 str 实现了).

Without it being stable, the Rust devs are very careful not to expose that feature somewhere in the standard library's public API. This doesn't mean that it isn't used at all in std! A famous example is the specialized ToString impl for str. It was introduced in this PR. As you can read in the PR's discussion, they only accepted it because it does not change the API (to_string() was already implemented for str).

然而,当我们添加上面的泛型实现时就不同了:它会改变 API.因此,它在 std 中还不允许.

However, it's different when we would add the generic impl above: it would change the API. Thus, it's not allowed in std yet.

core vs std:特征 FromInto定义在core,而 CloneToOwnedstd 中定义.这意味着我们不能在 core 中添加一个通用的 impl,因为 corestd 一无所知.但是我们也不能在 std 中添加泛型 impl,因为泛型 impl 需要与 trait 位于同一个 crate 中(这是孤儿规则的结果).

core vs std: the traits From and Into are defined in the core library, whereas Clone and ToOwned are defined in std. This means that we can't add a generic impl in core, because core doesn't know anything about std. But we also can't add the generic impl in std, because generic impls need to be in the same crate as the trait (it's a consequence of the orphan rules).

因此,在能够添加这样一个通用实现之前,它需要某种形式的重构和移动定义(这可能很难也可能不难).

Thus, it would required some form of refactoring and moving around definitions (which may or may not be difficult) before able to add such a generic impl.

<小时>

注意添加


Note that adding

impl<'a> From<&'a String> for String { ... }

... 工作得很好.它不需要专业化,也没有孤儿规则的问题.但当然,当通用 impl 有意义时,我们不想添加特定的 impl.

... works just fine. It doesn't require specialization and doesn't have problems with orphan rules. But of course, we wouldn't want to add a specific impl, when the generic impl would make sense.

(感谢 IRC 上可爱的人向我解释了一些东西)

这篇关于为什么 String 不实现 From&lt;&amp;String&gt;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆