Zombo
Zombo

Reputation: 1

Fold with string array

I tried some code like this:

fn main() {
   let a = vec!["May", "June"];
   let s = a.iter().fold("", |s2, s3|
      s2 + s3
   );
   println!("{}", s == "MayJune");
}

Result:

error[E0369]: cannot add `&&str` to `&str`
 --> a.rs:4:10
  |
4 |       s2 + s3
  |       -- ^ -- &&str
  |       |  |
  |       |  `+` cannot be used to concatenate two `&str` strings
  |       &str
  |
help: `to_owned()` can be used to create an owned `String` from a string
reference. String concatenation appends the string on the right to the string
on the left and may require reallocation. This requires ownership of the string
on the left
  |
4 |       s2.to_owned() + s3
  |       ^^^^^^^^^^^^^

Ok, fair enough. So I change my code to exactly that. But then I get this:

error[E0308]: mismatched types
 --> a.rs:4:7
  |
4 |       s2.to_owned() + s3
  |       ^^^^^^^^^^^^^^^^^^
  |       |
  |       expected `&str`, found struct `std::string::String`
  |       help: consider borrowing here: `&(s2.to_owned() + s3)`

Ok, fair enough. So I change my code to exactly that. But then I get this:

error[E0515]: cannot return reference to temporary value
 --> a.rs:4:7
  |
4 |       &(s2.to_owned() + s3)
  |       ^--------------------
  |       ||
  |       |temporary value created here
  |       returns a reference to data owned by the current function

Why is Rust giving bogus suggestion, and is what I am trying to do possible? Note, I would prefer to avoid suggestions such as "just use join" or similar, as this question is intended to address a more generic problem. Rust version:

rustc 1.46.0 (04488afe3 2020-08-24)

Upvotes: 2

Views: 907

Answers (1)

Masklinn
Masklinn

Reputation: 42612

is what I am trying to do possible?

Stargazeur provided a working version in their comment: the initial value / accumulator needs to be a String rather than an &str.

Why is Rust giving bogus suggestion

Rustc doesn't have a global-enough vision so it is able to see the "detail" issue but it doesn't realise that it's really a local effect of a larger problem: fold's signature is

fn fold<B, F>(self, init: B, f: F) -> B 

because you're giving fold an &str, it must ultimately return an &str, which is only possible if F just returns something it gets from "the outside", not if it creates anything internally. Since you want to create something inside your callback, the value of init is the issue.

Rustc doesn't see the conflict at that level though, because as far as it's concerned that's a perfectly valid signature e.g. you might be following a chain of things through a hashmap of returning a constant string reference for all it cares, the only real conflict it sees is between this:

 F: FnMut(B, Self::Item) -> B

and the implementation of your function which doesn't actually work, so it tries to help you with that:

  • Rust doesn't allow adding two &str together because that would implicitly allocate a String which is the sort of hidden concern the core team would rather not hide, so Add is only implemented between String and &str, that's the first issue you see, and since that's somewhat unusual (the average language just lets you concatenate string-ish stuff or even not-at-all-strings to strings) rustc devs have added a help text noting that the LHS must be an owned String, which generally helps / works but
  • then the addition returns a String, so now your function doesn't match the F signature anymore: since the init is an &str that's the type of the accumlator so you need to return an &str
  • except if you try to create a reference to the string you've just created, you just created it inside the function, once the function returns the string will be dead and the reference left dangling, which rust can not allow

And that's how despite the best intentions, because the compiler's view is too local it guilelessly leads you down a completely useless path of frustration.

You may want to report this issue on the bug tracker (or see if it's already there). I don't know if the compiler diagnostics system would be able to grok this situation though.

Upvotes: 3

Related Questions