Your code example is not very complete. The part that actually causes the error can't be seen in your example.
I guess that your code looks something like this:
pub fn function1(s: String) -> i32 {
let index: &i32 = &1;
let substring = (&s[index..]).to_string();
let counter = function1(substring);
10
}
error[E0277]: the type `String` cannot be indexed by `RangeFrom<&i32>`
--> src/main.rs:3:23
|
3 | let substring = (&s[index..]).to_string();
| ^^^^^^^^^^ `String` cannot be indexed by `RangeFrom<&i32>`
|
= help: the trait `Index<RangeFrom<&i32>>` is not implemented for `String`
Problems
indexmust be ausize, but it is an&i32. This is the main error that you see.- You cannot slice a string directly, you need to convert from char-based indices to byte-based indices first. This can be done by iterating through
char_indices().
Here is a rough sketch of how this might look like:
pub fn function1(s: String) -> i32 {
println!("s: {}", s);
let index: &i32 = &1;
// Try to convert the index to a byte position
let substring = match s.char_indices().nth(*index as usize) {
// If a position with the given index was found in the string, create a substring
Some((pos, _)) => (&s[pos..]).to_string(),
// Else, create an empty string
None => "".to_string(),
};
// Break if the substring is empty, otherwise we would have an infinite recursion
if substring.is_empty() {
return 0;
}
let counter = function1(substring);
counter + 1
}
fn main() {
let input_str = "".to_string();
let result = function1(input_str);
println!("Result: {}", result);
}
s:
s:
s:
s:
Result: 3
Slicing vs copying
With every iteration of your function, you are creating a new copy of the string. This is quite slow, and I don't see a reason why this would be necessary in your case.
What you really want is a slice of the input string. This doesn't copy any data, it simply references a part of the original string.
To achieve that, you would have to change your parameter type from String to &str. There is no reason your function would need to take ownership. Even if you want to take ownership, then to_string() would do so, as it creates a copy of the data. So there really is no reason to use String as the parameter type.
pub fn function1(s: &str) -> i32 {
println!("s: {}", s);
let index: &i32 = &1;
// Try to convert the index to a byte position
let substring = match s.char_indices().nth(*index as usize) {
// If a position with the given index was found in the string, create a substring slice
Some((pos, _)) => &s[pos..],
// Else, use an empty string
None => "",
};
// Break if the substring is empty, otherwise we would have an infinite recursion
if substring.is_empty() {
return 0;
}
let counter = function1(substring);
counter + 1
}
fn main() {
let input_str = "".to_string();
let result = function1(&input_str);
println!("Result: {}", result);
}
s:
s:
s:
s:
Result: 3
Answer from Finomnis on Stack OverflowVideos
How to get a substring of a String
Newbie Question: String Slices
&str is same with slice?
Basic-Topic-String-and-string-Slice
Your code example is not very complete. The part that actually causes the error can't be seen in your example.
I guess that your code looks something like this:
pub fn function1(s: String) -> i32 {
let index: &i32 = &1;
let substring = (&s[index..]).to_string();
let counter = function1(substring);
10
}
error[E0277]: the type `String` cannot be indexed by `RangeFrom<&i32>`
--> src/main.rs:3:23
|
3 | let substring = (&s[index..]).to_string();
| ^^^^^^^^^^ `String` cannot be indexed by `RangeFrom<&i32>`
|
= help: the trait `Index<RangeFrom<&i32>>` is not implemented for `String`
Problems
indexmust be ausize, but it is an&i32. This is the main error that you see.- You cannot slice a string directly, you need to convert from char-based indices to byte-based indices first. This can be done by iterating through
char_indices().
Here is a rough sketch of how this might look like:
pub fn function1(s: String) -> i32 {
println!("s: {}", s);
let index: &i32 = &1;
// Try to convert the index to a byte position
let substring = match s.char_indices().nth(*index as usize) {
// If a position with the given index was found in the string, create a substring
Some((pos, _)) => (&s[pos..]).to_string(),
// Else, create an empty string
None => "".to_string(),
};
// Break if the substring is empty, otherwise we would have an infinite recursion
if substring.is_empty() {
return 0;
}
let counter = function1(substring);
counter + 1
}
fn main() {
let input_str = "".to_string();
let result = function1(input_str);
println!("Result: {}", result);
}
s:
s:
s:
s:
Result: 3
Slicing vs copying
With every iteration of your function, you are creating a new copy of the string. This is quite slow, and I don't see a reason why this would be necessary in your case.
What you really want is a slice of the input string. This doesn't copy any data, it simply references a part of the original string.
To achieve that, you would have to change your parameter type from String to &str. There is no reason your function would need to take ownership. Even if you want to take ownership, then to_string() would do so, as it creates a copy of the data. So there really is no reason to use String as the parameter type.
pub fn function1(s: &str) -> i32 {
println!("s: {}", s);
let index: &i32 = &1;
// Try to convert the index to a byte position
let substring = match s.char_indices().nth(*index as usize) {
// If a position with the given index was found in the string, create a substring slice
Some((pos, _)) => &s[pos..],
// Else, use an empty string
None => "",
};
// Break if the substring is empty, otherwise we would have an infinite recursion
if substring.is_empty() {
return 0;
}
let counter = function1(substring);
counter + 1
}
fn main() {
let input_str = "".to_string();
let result = function1(&input_str);
println!("Result: {}", result);
}
s:
s:
s:
s:
Result: 3
You couldn't indexing a string in rust, because strings are encoded in UTF-8.
You could use the method chars and/or char_indices
As from your given code, I can't figure out what method you should use. Have a look at the rust doc.
For further information:
https://doc.rust-lang.org/std/string/struct.String.html
https://doc.rust-lang.org/std/string/struct.String.html#method.chars
https://doc.rust-lang.org/std/string/struct.String.html#method.char_indices
https://doc.rust-lang.org/std/string/struct.String.html#method.split_whitespace
I am coming from a world of Python, so pointers and references are kind of a new thing for me. So, I was going through The book. I was on the slices chapter, specifically the String Slices as Parameter part. I just don't get this fn first_word(s: &String) -> &str { is worse than fn first_word(s: &str) -> &str { this. Is it because it is a pointer to a pointer, if I understood things correctly?
You can't return a reference to a locally allocated String because the string is dropped when the function returns. There's no way to finagle your way around that. A &str is simply a bad match for the type of data you want to return.
The most straightforward fix is to return an owned String.
Copyfn my_func(input: &str) -> String {
match input {
"a" => "Alpha".to_string(),
_ => format!("'{}'", "Quoted" ),
}
}
Another is to return a Cow<'_, str>, which can hold either a borrowed or owned string depending on which you have. It's a bit fussy, but it does avoids unnecessary allocations. I only recommend this if efficiency is of utmost important; otherwise, just return String.
Copyfn my_func(input: &str) -> Cow<'_, str> {
match input {
"a" => "Alpha".into(),
_ => format!("'{}'", "Quoted" ).into(),
}
}
I'll also mention a third option -- for educational purposes, not for actual use, since it leaks memory. You can get a 'static reference to an owned object if you leak it. Leaked memory is valid for the remainder of the program since it's never freed, and thus you can in fact get a reference to it.
Copy// Warning: Do not use! Leaks memory.
fn my_func(input: &str) -> &'static str {
match input {
"a" => "Alpha",
_ => Box::leak(format!("'{}'", "Quoted").into_boxed_str()),
}
}
The problem is that the arm with format!().as_str() produces an owned String, as soon as your function returns, the String is dropped and the &str reference would become invalid.
You can use std::borrow::Cow to allow a function to return both owned or borrowed strings.
Hey all,
I am learning Rust, and was not sure how to approach the following:
Write a function `first_char` that takes a string slice and returns a reference to its first character.`
My attempt:
fn first_char(s: &str) -> Option<&char> {
s.chars().next().as_ref()
}However, Rust complains that it "cannot return value referencing temporary value
returns a value referencing data owned by the current function"
Is there any way to solve the above? Any pointers would be appreciated