I'm working my way through the rust book. In the Strings chapter a lot of the examples use to_string() which my version of the compiler(rustc 1.0.0-dev) gives the following warning
strings.rs:3:23: 3:34 warning: use of unstable item, #[warn(unstable)] on by default
strings.rs:3 let mut s = "Hello".to_string();
Code:
fn main() {
let mut s = "Hello".to_string();
println!("{}", s);
}
I understand from this question that this is because the API is likely to change, but I would like to know what I should use instead if I want to convert a string slice (str&) to a String
You can work around these things, e.g. format!("Hello"), but I really wouldn’t bother for the moment.
Related
I'm getting into Rust and Arduino at the same time.
I was programming my LCD display to show a long string by rotating it through the top column of characters. Means: Every second I shift all characters by one position and show the new String.
This was fairly complex in the Arduino language, especially because I had to know the size of the String at compile time (given my limited knowledge).
Since I'd like to use Rust in the long term, I was curious to see if that could be done more easily in a modern language. Not so much.
This is the code I came up with, after hours of experimentation:
#![no_std]
extern crate alloc;
use alloc::{vec::Vec};
fn main() {
}
fn rotate_by<T: Copy>(rotate: Vec<T>, by: isize) -> Vec<T> {
let real_by = modulo(by, rotate.len() as isize) as usize;
Vec::from_iter(rotate[real_by..].iter().chain(rotate[..real_by].iter()).cloned())
}
fn modulo(a: isize, b: isize) -> isize {
a - b * (a as f64 /b as f64).floor() as isize
}
mod tests {
use super::*;
#[test]
fn test_rotate_five() {
let chars: Vec<_> = "I am the string and you should rotate me! ".chars().collect();
let res_chars: Vec<_> = "the string and you should rotate me! I am ".chars().collect();
assert_eq!(rotate_by(chars, 5), res_chars);
}
}
My questions are:
Could you provide an optimized version of this function? I'm aware that there already is Vec::rotate but it uses unsafe code and can panic, which I would like to avoid (by returning a Result).
Explain whether or not it is possible to achieve this in-place without unsafe code (I failed).
Is Vec<_> the most efficient data structure to work with? I tried hard to use [char], which I thought would be more efficient, but then I have to know the size at compile time, which hardly works. I thought Rust arrays would be similar to Java arrays, which can be sized at runtime yet are also fixed size once created, but they seem to have a lot more constraints.
Oh and also what happens if I index into a vector at an invalid index? Will it panic? Can I do this better? Without "manually" checking the validity of the slice indices?
I realize that's a lot of questions, but I'm struggling and this is bugging me a lot, so if somebody could set me straight it would be much appreciated!
You can use slice::rotate_left and slice::rotate_right:
#![no_std]
extern crate alloc;
use alloc::vec::Vec;
fn rotate_by<T>(data: &mut [T], by: isize) {
if by > 0 {
data.rotate_left(by.unsigned_abs());
} else {
data.rotate_right(by.unsigned_abs());
}
}
I made it rotate in-place because that is more efficient. If you don't want to do it in-place you still have the option of cloning the vector first, so this is more flexible than if the function creates a new vector, as you have done, because you aren't be able to opt out of that when you call it.
Notice that rotate_by takes a mutable slice, but you can still pass a mutable reference to a vector, because of deref coercion.
#[test]
fn test_rotate_five() {
let mut chars: Vec<_> = "I am the string and you should rotate me! ".chars().collect();
let res_chars: Vec<_> = "the string and you should rotate me! I am ".chars().collect();
rotate_by(&mut chars, 5);
assert_eq!(chars, res_chars);
}
There are some edge cases with moving chars around like this because some valid UTF-8 will contain grapheme clusters that are made up of multiple codepoints (chars in Rust). This will result in strange effects when a grapheme cluster is split between the start and end of the string. For example, rotating "abcdéfghijk" by 5 will result in "efghijkabcd\u{301}", with the acute accent stranded on its own, away from the 'e'.
If your strings are ASCII then you don't have to worry about that, but then you can also just treat them as byte strings anyway:
#[test]
fn test_rotate_five_ascii() {
let mut chars = b"I am the string and you should rotate me! ".clone();
let res_chars = b"the string and you should rotate me! I am ";
rotate_by(&mut chars, 5);
assert_eq!(chars, &res_chars[..]);
}
I've seen a lot of usage of Box::new in Rust language.
https://doc.rust-lang.org/book/ch15-01-box.html
fn main() {
let b = Box::new(5);
println!("b = {}", b);
}
However, I think this is a bit redundant, especially, in the code like this:
enum List {
Cons(i32, Box<List>),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}
Now, I want to write in a concise way using Macro as we've seen as vec!
https://doc.rust-lang.org/book/ch19-06-macros.html?highlight=vec#declarative-macros-with-macro_rules-for-general-metaprogramming
let v: Vec<u32> = vec![1, 2, 3];
so that with box! macro, we could write:
fn main() {
let b = box!(5);
println!("b = {}", b);
}
or
fn main() {
let list = Cons(1, box!(Cons(2, box!(Cons(3, box!(Nil))))));
}
My question is
Is there any reason that box! macro is not popular even it's
used frequently in Rust?
What is the proper way to define the macro? Is there any points of attention?
This is a bit subjective, but vectors are used far more often, I believe. And the vec! macro saves you a lot more code compared to the box! macro you are referring to.
As for the macro implementation, you can write something like this:
macro_rules! bx {
($e:expr) => {
Box::new($e)
};
}
Here is an example usage:
let b = Box::new(3);
let m = bx!(7);
Note that I named it bx! and not box!, as the latter is a reserved word in Rust.
however, for some unknown reason Rust guys prefer to use macro for vec! or println!
I suggest asking this the other way around: why couldn't vec! and println! be functions? And the answer is, both are variadic (can take variable number of arguments) and there are no variadic functions in Rust. It's much worse for println!, whose arguments can have different types too; and constraints on those types depend on the first argument! Try writing down a type for println as a function, and you'll find it would be much less usable and less efficient.
The problem vec! solves is smaller. But as Chayim Friedman's comment says, until quite recently you couldn't even have had
Vec::from([1,2,3])
if there were no vec! macro. I think the best you could have done was
Vec::from(&[1,2,3])
As Chayim points out, this is strictly worse than vec!.
Of course, Box::new doesn't have this problem at all. So it's a function just because it didn't have to be a macro.
but as I post the Cons list expample, it's obvious the latter syntax is redundant and does have an issue for readability
In that case box! is no less redundant; instead a way to get rid of redundancy is
fn cons(head: i32, tail: List) -> List {
List::Cons(head, Box::new(tail))
}
and then
let list = cons(1, cons(2, cons(3, Nil)));
Or even a list! macro and
let list = list![1,2,3];
Thanks to #at54321, I googled and found
https://doc.rust-lang.org/beta/unstable-book/language-features/box-syntax.html
#![feature(box_syntax)]
fn main() {
let b = box 5;
}
So, already there.
So for easy initialization of a vector there is there vec! macro.
let mut vec_of_zeroes: Vec<usize> = vec![0;10];
I was wondering if there was an easy standard macro for initializing a linked list too?
use std::collections::LinkedList;
let mut list_of_zeroes: LinkedList<usize> = /*macro here?*/;
If not, no worries. Thanks for you time.
No, there is no such macro in the standard library. Indeed, there is no analogous macro for any other data structure, even HashMap / BTreeMap, which are much more frequently used.
However, the crate velcro provides a linked_list! macro that does what you want (and has some other neat features).
Note that std::collections::LinkedList lacks some features that make linked lists attractive - there is no cursor-based API, for instance. In most cases you should probably use Vec or VecDeque instead.
There is no linked list macro, but you could use the .extend() method to achieve something similar:
use std::collections::LinkedList;
fn main() {
let mut a: LinkedList<u32> = LinkedList::new();
a.extend(&[0; 10]);
println!("{:?}", a);
}
Playground
If you want to have a single line initialization, you could use some other iterator methods as suggested by #Stargateur in the comments. This method also allows the variable to be immutable, if you wanted that for some reason.
use std::collections::LinkedList;
fn main() {
let a: LinkedList<u32> = [0; 10].iter().copied().collect();
println!("{:?}", a);
}
Playground
I can convert Vec<String> to Vec<&str> this way:
let mut items = Vec::<&str>::new();
for item in &another_items {
items.push(item);
}
Are there better alternatives?
There are quite a few ways to do it, some have disadvantages, others simply are more readable to some people.
This dereferences s (which is of type &String) to a String "right hand side reference", which is then dereferenced through the Deref trait to a str "right hand side reference" and then turned back into a &str. This is something that is very commonly seen in the compiler, and I therefor consider it idiomatic.
let v2: Vec<&str> = v.iter().map(|s| &**s).collect();
Here the deref function of the Deref trait is passed to the map function. It's pretty neat but requires useing the trait or giving the full path.
let v3: Vec<&str> = v.iter().map(std::ops::Deref::deref).collect();
This uses coercion syntax.
let v4: Vec<&str> = v.iter().map(|s| s as &str).collect();
This takes a RangeFull slice of the String (just a slice into the entire String) and takes a reference to it. It's ugly in my opinion.
let v5: Vec<&str> = v.iter().map(|s| &s[..]).collect();
This is uses coercions to convert a &String into a &str. Can also be replaced by a s: &str expression in the future.
let v6: Vec<&str> = v.iter().map(|s| { let s: &str = s; s }).collect();
The following (thanks #huon-dbaupp) uses the AsRef trait, which solely exists to map from owned types to their respective borrowed type. There's two ways to use it, and again, prettiness of either version is entirely subjective.
let v7: Vec<&str> = v.iter().map(|s| s.as_ref()).collect();
and
let v8: Vec<&str> = v.iter().map(AsRef::as_ref).collect();
My bottom line is use the v8 solution since it most explicitly expresses what you want.
The other answers simply work. I just want to point out that if you are trying to convert the Vec<String> into a Vec<&str> only to pass it to a function taking Vec<&str> as argument, consider revising the function signature as:
fn my_func<T: AsRef<str>>(list: &[T]) { ... }
instead of:
fn my_func(list: &Vec<&str>) { ... }
As pointed out by this question: Function taking both owned and non-owned string collections. In this way both vectors simply work without the need of conversions.
All of the answers idiomatically use iterators and collecting instead of a loop, but do not explain why this is better.
In your loop, you first create an empty vector and then push into it. Rust makes no guarantees about the strategy it uses for growing factors, but I believe the current strategy is that whenever the capacity is exceeded, the vector capacity is doubled. If the original vector had a length of 20, that would be one allocation, and 5 reallocations.
Iterating from a vector produces an iterator that has a "size hint". In this case, the iterator implements ExactSizeIterator so it knows exactly how many elements it will return. map retains this and collect takes advantage of this by allocating enough space in one go for an ExactSizeIterator.
You can also manually do this with:
let mut items = Vec::<&str>::with_capacity(another_items.len());
for item in &another_items {
items.push(item);
}
Heap allocations and reallocations are probably the most expensive part of this entire thing by far; far more expensive than taking references or writing or pushing to a vector when no new heap allocation is involved. It wouldn't surprise me if pushing a thousand elements onto a vector allocated for that length in one go were faster than pushing 5 elements that required 2 reallocations and one allocation in the process.
Another unsung advantage is that using the methods with collect do not store in a mutable variable which one should not use if it's unneeded.
another_items.iter().map(|item| item.deref()).collect::<Vec<&str>>()
To use deref() you must add using use std::ops::Deref
This one uses collect:
let strs: Vec<&str> = another_items.iter().map(|s| s as &str).collect();
Here is another option:
use std::iter::FromIterator;
let v = Vec::from_iter(v.iter().map(String::as_str));
Note that String::as_str is stable since Rust 1.7.
I want to play with BasicAuth stuff, therefore I need the base64 version of a string. So I needed a function : String to base_64(String).
In the string guides for Rust, most of the time $str is preferred to String. So I wanted to adjust to this idea.
But working with &str is somehow harder than it seems (I know that my problem is related to Question also about as_slice()).
The author of other question could solve his problem by not using as_slice(), is there a way to still work with &str for me?
extern crate serialize;
use serialize::base64::{ToBase64,MIME};
fn generate_base_string (n : &str) -> String {
let mut config = serialize::base64::MIME;
config.line_length = None;
let bytes: & [u8] = n.as_bytes();
return bytes.to_base64(config);
}
fn generate_base<'a> (n : &'a str ) -> &'a str {
let mut config = serialize::base64::MIME;
config.line_length = None;
let bytes: & [u8] = n.as_bytes();
let res2: String = bytes.to_base64(config);
let res1: &'a str = res2.as_slice();
return res1;
}
#[test]
fn right_base64() {
let trig :&str = generate_base("string");
assert!(trig=="c3RyaW5n");
}
// http://doc.rust-lang.org/guide-strings.html
#[test]
fn right_base64_string(){
// A `String` - a heap-allocated string
assert!(generate_base_string("string")=="c3RyaW5n".to_string());
}
These are my first baby steps in Rust so please be not to mean if I do something really wrong.
& is a pointer, it points to a memory that somebody else owns.
So, &str is a pointer to a string memory (slice) that somebody else owns.
String, on the other hand, is a string that owns its memory and keeps the characters there.
Now, when you generate a base64 you make something new, it's like hearing a piano concerto and catching it in an oil painting. Instead of taking your brush and making the painted version of the concerto you could just point to the original music, but that won't work when you specifically need a painted version. Similarly simply pointing to the original string won't work when you need a base64 version. You need to make something new, you need a canvas for it, that is the String.
What you're trying to do in fn generate_base<'a> (n : &'a str ) -> &'a str is akin to creating a painting, destroying it and pointing to the destroyed painting. Look at the painting I made!.. only I've burned it. That's against the Rust safety rules, you shouldn't point to something which no longer exists (it's also known as a "dangling pointer").
String is not evil, don't be afraid to use a new String when you're creating something new.
But why people avoid String? It's because passing String is like passing the real painting. Imagine a museum taking the Leonardo from the wall and giving it to you: here, take it for a walk, enjoy. Now that you've taken it, nobody else will see it in the museum. And you'll have to give it back. It's often easier to simply visit the museum and look at the thing, without moving it anywhere.