3

I'm new to Rust and I'm currently reading The Rust Programming Language book.

I'm curious about this example:

fn main() {
    let s1 = String::from("Hello, ");
    let s2 = String::from("world!");
    let s3 = s1 + &s2; // note s1 has been moved here and can no longer be used
}

Is it possible to take ownership not only of s1, but also of s2, so s2 gets invalidated as well as s1, making s3 the only possible variable that remains usable?

4
  • Why? Sounds like an X/Y problem. Commented Feb 13, 2021 at 17:36
  • @mcarton I was actually more curious about if it's possible to make a string without explicitly copying the contents of one of the strings. Basically, the new string should contain 2 pointers of type String one after another. Now I realized that this should be a custom type, and it's not possible using the default String implementation. It's more of a theoretical question, that asks for language-specific design, that is yet not that well known by me. Commented Feb 13, 2021 at 18:39
  • @cr7pt0pl4gu3 no, in order to concatenate the strings there needs to be a single contiguous allocation. But even if they happened to be next to one another in physical memory (which is not likely) s1 and s2 are different allocations. So the best you can do in the standard library is append s2 at the end of s1's buffer. Commented Feb 13, 2021 at 19:05
  • 1
    Although outside of the standard library there might be a ropes lib: ropes are pseudo-strings designed as a shallow tree of buffers, the primary goal is to easily update segments of text in-place, without the need to move a lot of data around. But a side-effect is that a rope concatenates two strings by just referencing both. Commented Feb 13, 2021 at 19:06

1 Answer 1

5

Updated Answer

This is not possible. A String has to be a single contiguous allocation in memory. If you want to roll your own simple solution you can probably define a type like this:

struct MyString {
    parts: Vec<String>,
}

impl MyString {
    fn concat(&mut self, other: String) {
        self.parts.push(other);
    }
}

However re-implementing every useful String method for this custom type is going to be tedious and error-prone. You can find a Rust crate which implements a Rope data structure, and an-rope seems to be such a crate, but only a tiny fraction of String methods are supported.


I gave this answer when I interpreted OP's question as one about invalidating and moving variables:

Original Answer

You can invalidate any non-Copy variable by moving it somewhere else, like by passing it to the drop function:

fn main() {
    let s1 = String::from("Hello, ");
    let s2 = String::from("world!");
    let s3 = s1 + &s2; // s1 invalidated
    drop(s2); // s2 invalidated
    // now only s3 is usable
}

If this is a common pattern in your application you can just write a function which takes ownership of 2 Strings and returns the concatenated result:

fn concat(s1: String, s2: String) -> String {
    s1 + &s2
}

fn main() {
    let s1 = String::from("Hello, ");
    let s2 = String::from("world!");
    let s3 = concat(s1, s2); // s1 & s2 invalidated
    // now only s3 is usable
}
Sign up to request clarification or add additional context in comments.

1 Comment

@cr7pt0pl4gu3 Do note that this does not prevent copying of the second String, so disabling its ownership is kind of pointless.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.