Wednesday, July 6, 2022

[FIXED] How does this recursive join work in Rust

Issue

So I wrote this recursive string join function in Rust which seems to work, but I'm a bit confused why it works.

fn join(separator: &str, strs: &[&str]) -> String {
    match strs.len() {
        l if l > 1    => return strs[0].to_string() + separator + &join(separator, &strs[1..]),
        l if l == 1   => return strs[0].to_string(),
        _             => return "".to_string(),
    }
}

So I have an array of 3 Strings that I would like to join and a String separator. The function takes in the reference to a str &str for its first argument and then a reference to an array of Strings &[&str] for the second argument.

let j1 = ["one", "two", "three"];
println!("{}", join(", ", &j1));
  1. Why does the recursive join have to be defined as &join(separator, &strs[1..])?
  2. why does &strs[1..] have to be dereferenced again?

Solution

  1. std::ops::Add<&'_ str> is implemented for String (scroll to the very bottom of the page). std::ops::Add<String> is not. Hence, you can only add &'_ strs to Strings, and only on the right hand side. You have to reference your call to join because that uses deref coercion to turn the String into a &str.

  2. This one is a bit more convoluted to provide exact evidence for, but in simplest terms, slicing (using a range in the index position) a slice or array will produce a slice, IE, [T]. Since you can't pass around bare [T]s around, you need to take a reference to it.
    The more exact reason as to why is:


Additionally, this isn't the most idiomatic way of writing this function:

pub fn join(separator: &str, strs: &[&str]) -> String {
    match strs {
        [last]               => last.to_string(),
        [current, rest @ ..] => current.to_string() + separator + &join(separator, &rest),
        []                   => "".to_string(),
    }
}

Pattern matching works on slices.



Answered By - Optimistic Peach
Answer Checked By - Clifford M. (PHPFixing Volunteer)

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.