struct AA<'t> {
kk: Vec<&'t str>
}
fn new<'t>(dd: String) -> AA<'t> {
//dd is a very large string, and dd can't be changed to &'str.
//want to return the struct AA
//If kk is changed to Vec<String>, memory may be doubled.
//So I want Vec<&'t str> to be a reference to the dd string, how do I do that?
todo!()
}
You (normally) can't create self-referential structs in Rust. A solution is to keep a String
outside the struct:
struct AA<'t> {
kk: Vec<&'t str>
}
fn new<'t>(dd: &'t String) -> AA<'t> {
AA {
kk: vec![dd],
}
}
fn main() {
let s = String::from("Hello");
let _aa = new(&s);
}
Edit: Actually you could/should write &'t str
for the type of dd
, but I just noticed that's exactly what you wanted to avoid.
The other thing you can do is this:
struct AA {
dd: String,
kk: Vec<std::ops::Range<usize>>,
}
Then, if you want the i
th substring, you'd have:
impl AA {
fn ith_substr(&self, i: usize) -> &str {
&self.dd[self.kk[i]]
}
}
You likely misunderstand how this works. If you move the string dd
to the field kk
, nothing is copied. At least not the large backing buffer of the string. Only the (pointer, capacity, length) triple is moved around, which is very cheap.
Note that it's not possible to "return by reference". That simply doesn't make any sense as a concept. References are non-owning views into data. If you want to return data created in a function, you'll have to do that by returning a value.
And that's not "suboptimal" or "slow". You have to have an owner of the data somewhere.
let dd = "dddddd";
let mut bbb = vec![];
for _ in 1..1000000 {
bbb.push(dd [0..2].to_owned());
}
println!("{:?}", bbb);
dd is copy...
the dd var form ToDD,so
trait ToDD {
fn create_dd(&self) -> String;
}
fn new<'t>(dd_from: impl ToDD) -> AA<'t> {
let dd=dd_from. create_dd();
}
To simplify the problem, I've simplified the code this way.
I need to move dd into to function.
It's a workable solution, but it's too complicated. thk.
thk
Such a treatment cannot be used with the following code
struct NN {}
struct AA<'t> {
kk: Vec<&NN>,
}
fn new<'t>(dd: Vec<NN>) -> AA<'t> {
todo!()
}
In what way? It's as simple as it gets. You store the ranges, you query the string when you need slices. The whole answer contains 9 lines of code. If that's too complicated for you, we likely won't be able to help.
In this case you can store dd
along with a Vec<usize>
containing indexes into kk
rather than references.
That or look into some self-referential (that's the name of what you likely want) crate, like ouroboros
.
For future reference, whenever you're trying to write a function that requires something with a lifetime (e.g. AA<'t>
here) but there's nothing with a lifetime in input to the function then you're 99% trying to do something impossible, and you should stop and reason about who owns what. In your example here dd
is a Vec
owned by the function which will be destroyed when the function ends, so there's no way AA
will be able to borrow from it.
This. Thank you for saying that. There was a very similar question yesterday with something like
impl<'a> Struct<'a> {
fn new() -> Struct<'a> {
// self-referential crimes
}
}
and I knew from the signature it's going to be troublesome, but I was too lazy to phrase it adequately while on my phone.
One of the nice things about Rust is you can't accidentally copy a String's content. If you're trying to avoid that copy, you'll know you're on the right track if you never use .clone(), .to_owned(), .into(), etc. So,
struct AA {
kk: Vec<String>,
}
fn new(dd: String) -> AA {
AA { kk: vec![dd] }
}
Doesn't copy.
I had exactly the same thought a couple of days ago when reasoning about the combination of the NewType
pattern for ID types, such as:
struct MyLittleId(Uuid);
struct MyStruct {
id: MyLittleId,
...
}
In GC languages, it's easier that a developer assigns the supposedly-unique id field when touching the codebase, while in Rust you would need to explicitly derive or implement the Clone
and/or Copy
traits on the MyLittleId
type in order for you to be able to make such mistake. This alone increases the chances of such mistake getting caught either by the developer or during code review.