为什么 String 不实现 From<&String>? [英] Why doesn't String implement 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 String
s, 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:
特化:允许重叠 trait-impls 的特化特性仍然不稳定.事实证明,以合理的方式设计专业化比更难预期(主要是由于生命周期).
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
:特征 From
和 Into
定义在core
库,而 Clone
和 ToOwned
在 std
中定义.这意味着我们不能在 core
中添加一个通用的 impl,因为 core
对 std
一无所知.但是我们也不能在 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<&String>?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!