19
votes

This is for the current 0.6 Rust trunk by the way, not sure the exact commit.

Let's say I want to for each over some strings, and my closure takes a borrowed string pointer argument (&str). I want my closure to add its argument to an owned vector of owned strings ~[~str] to be returned. My understanding of Rust is weak, but I think that strings are a special case where you can't dereference them with * right? How do I get my strings from &str into the vector's push method which takes a ~str?

Here's some code that doesn't compile

fn read_all_lines() -> ~[~str] {
    let mut result = ~[];
    let reader = io::stdin();
    let util = @reader as @io::ReaderUtil;
    for util.each_line |line| {
        result.push(line);
    }
    result
}

It doesn't compile because it's inferring result's type to be [&str] since that's what I'm pushing onto it. Not to mention its lifetime will be wrong since I'm adding a shorter-lived variable to it.

I realize I could use ReaderUtil's read_line() method which returns a ~str. But this is just an example.

So, how do I get an owned string from a borrowed string? Or am I totally misunderstanding.

3
This is less relevant now given that Rust is at 1.X. (Rust 1.X uses String and &str, not ~str) So, it would be helpful to label this as pre-Rust 1.0. My hope is that search engine relevance could be adjusted accordingly.David J.
I could be out of line here, but I have voted to close this question as it does not apply to current Rust syntax, which does not include ~Richard Neish

3 Answers

11
votes

You should call the StrSlice trait's method, to_owned, as in:

fn read_all_lines() -> ~[~str] {
    let mut result = ~[];
    let reader = io::stdin();
    let util = @reader as @io::ReaderUtil;
    for util.each_line |line| {
        result.push(line.to_owned());
    }
    result
}

StrSlice trait docs are here:

http://static.rust-lang.org/doc/core/str.html#trait-strslice

4
votes

You can't.

For one, it doesn't work semantically: a ~str promises that only one thing owns it at a time. But a &str is borrowed, so what happens to the place you borrowed from? It has no way of knowing that you're trying to steal away its only reference, and it would be pretty rude to trash the caller's data out from under it besides.

For another, it doesn't work logically: ~-pointers and @-pointers are allocated in completely different heaps, and a & doesn't know which heap, so it can't be converted to ~ and still guarantee that the underlying data lives in the right place.

So you can either use read_line or make a copy, which I'm... not quite sure how to do :)

I do wonder why the API is like this, when & is the most restricted of the pointers. ~ should work just as well here; it's not like the iterated strings already exist somewhere else and need to be borrowed.

4
votes

At first I thought it was possible to use copy line to create owning pointer from the borrowed pointer to the string but this apparently copies burrowed pointer.

So I found str::from_slice(s: &str) -> ~str. This is probably what you need.