Skip to content

Commit 369c528

Browse files
committed
initial commit
Signed-off-by: Chawye Hsu <[email protected]>
0 parents  commit 369c528

File tree

8 files changed

+179
-0
lines changed

8 files changed

+179
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target

Cargo.lock

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "to_string-vs-to_owned"
3+
version = "0.1.0"
4+
authors = ["Chawye Hsu <[email protected]>"]
5+
edition = "2018"
6+
7+
[dependencies]

README.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
`to_string` or `to_owned`?
2+
---
3+
4+
**Q**: In Rust, both `to_string()` and `to_owned()` can be used to convert a
5+
[`&str`][1] to a [`String`][2]. So what is the idiomatic way to do this
6+
conversion? Do they have any performance differences?
7+
8+
**A**: The answer for the question of performance differences is **NO**. These
9+
two methods do not have any performance difference. Let's take a look at the
10+
source code of these two methods.
11+
12+
**to_string**:
13+
```rust
14+
// alloc::string
15+
#[stable(feature = "str_to_string_specialization", since = "1.9.0")]
16+
impl ToString for str {
17+
#[inline]
18+
fn to_string(&self) -> String {
19+
String::from(self)
20+
}
21+
}
22+
```
23+
24+
**to_owned**:
25+
```rust
26+
// alloc::str
27+
#[stable(feature = "rust1", since = "1.0.0")]
28+
impl ToOwned for str {
29+
type Owned = String;
30+
#[inline]
31+
fn to_owned(&self) -> String {
32+
unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) }
33+
}
34+
35+
fn clone_into(&self, target: &mut String) { ... }
36+
}
37+
```
38+
39+
As we can see, `to_string()` just calls `String::from`. Let's dive into it.
40+
41+
```rust
42+
// alloc::string
43+
#[stable(feature = "rust1", since = "1.0.0")]
44+
impl From<&str> for String {
45+
#[inline]
46+
fn from(s: &str) -> String {
47+
s.to_owned()
48+
}
49+
}
50+
```
51+
52+
So actually it just calls `to_owned()`. Since they're all inlined, thus there’s
53+
no extra performance cost. Therefore you can use whichever you feel like, there's
54+
no *idiomatic way*.
55+
56+
#### bonus
57+
58+
In fact, `into()` also can be used to convert a `&str` to a `String`, but this
59+
way requires a type annotation for the variable.
60+
61+
```rust
62+
let s: String = "hello, rust!".into();
63+
```
64+
65+
And a `String` annotated call to `into()` just calls `String::from`, which is
66+
the same function `to_string()` calls.
67+
68+
```rust
69+
// core::convert
70+
71+
// From implies Into
72+
#[stable(feature = "rust1", since = "1.0.0")]
73+
impl<T, U> Into<U> for T
74+
where
75+
U: From<T>,
76+
{
77+
fn into(self) -> U {
78+
U::from(self)
79+
}
80+
}
81+
```
82+
83+
Although there's no extra performance cost to any of them, they're different
84+
semantically.
85+
86+
- `to_owned()`: I have a borrowed object and I want an owned version
87+
- `to_string()`: I want the textual representation of something
88+
- `into()`: I want a generic type conversion
89+
90+
Therefore, it's better to choose the proper method according to the semantic
91+
context of the code logic you're writing. For converting `&str` to `String`,
92+
I prefer `to_owned()` over the others as per semantics. The difference between
93+
`String` ans `&str` is the ownership, one is owned and the other is not owned.
94+
95+
#### Why you wrote this?
96+
97+
Just like any google oriented programmer, there are often questions that come
98+
from my mind when I'm learning a new thing. I want to know the difference
99+
between `to_owned()` and `to_string()`, then I googled `to_string to_owned` and
100+
the first result it gives me was [Converting &str: to_string vs to_owned (with two benchmarks)][3]. I read the post and coundn't believe the performance difference
101+
they said. After more researches I realized that the post is wrong (or maybe is
102+
outdated becuase it was posted in 2016), and I worried about there might be other
103+
new Rustaceans read that post reached from google search and get the outdated
104+
conclusion. Therefore I wrote this with the name `to_string or to_owned?` for
105+
easy searching purpose, and this is the reason.
106+
107+
### References
108+
109+
- [`to_string()` vs `to_owned()` for string literals][4]
110+
- [What is the idiomatic way to convert &str to String?][5]
111+
112+
[1]: https://doc.rust-lang.org/std/primitive.str.html
113+
[2]: https://doc.rust-lang.org/std/string/struct.String.html
114+
[3]: https://medium.com/@ericdreichert/converting-str-to-string-vs-to-owned-with-two-benchmarks-a66fd5a081ce
115+
[4]: https://users.rust-lang.org/t/to-string-vs-to-owned-for-string-literals/1441
116+
[5]: https://users.rust-lang.org/t/what-is-the-idiomatic-way-to-convert-str-to-string/12160

UNLICENSE

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
This is free and unencumbered software released into the public domain.
2+
3+
Anyone is free to copy, modify, publish, use, compile, sell, or
4+
distribute this software, either in source code form or as a compiled
5+
binary, for any purpose, commercial or non-commercial, and by any
6+
means.
7+
8+
In jurisdictions that recognize copyright laws, the author or authors
9+
of this software dedicate any and all copyright interest in the
10+
software to the public domain. We make this dedication for the benefit
11+
of the public at large and to the detriment of our heirs and
12+
successors. We intend this dedication to be an overt act of
13+
relinquishment in perpetuity of all present and future rights to this
14+
software under copyright law.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22+
OTHER DEALINGS IN THE SOFTWARE.
23+
24+
For more information, please refer to <http://unlicense.org/>

benches/bench.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![feature(test)]
2+
extern crate test;
3+
4+
#[bench]
5+
fn to_owned(bencher: &mut test::Bencher) {
6+
bencher.iter(|| {
7+
test::black_box(
8+
"hello, world!".to_owned()
9+
)
10+
});
11+
}
12+
13+
#[bench]
14+
fn to_string(bencher: &mut test::Bencher) {
15+
bencher.iter(|| {
16+
test::black_box(
17+
"hello, world!".to_string()
18+
)
19+
});
20+
}

rust-toolchain

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nightly

src/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
fn main() {
2+
println!("{}", "hello, to_owned!".to_owned());
3+
println!("{}", "hello, to_string!".to_string());
4+
let a: String = "d".into();
5+
}

0 commit comments

Comments
 (0)