How to format a String object in Rust? [duplicate] - rust

This question already has answers here:
println! error: expected a literal / format argument must be a string literal
(4 answers)
Closed 6 years ago.
I have a HashMap with endpoints:
#[derive(Debug, Clone, Copy, Ord, Eq, PartialOrd, PartialEq, Hash)]
enum Endpoint {
OauthToken,
Disciplines,
PublicTournaments,
MyTournaments,
Matches,
}
lazy_static! {
static ref API_EP: HashMap<Endpoint, &'static str> = {
let mut m: HashMap<Endpoint, &'static str> = HashMap::new();
m.insert(Endpoint::OauthToken, "/oauth/v2/token");
m.insert(Endpoint::Disciplines, "/v1/disciplines");
m.insert(Endpoint::PublicTournaments, "/v1/tournaments");
m.insert(Endpoint::MyTournaments, "/v1/me/tournaments");
m.insert(Endpoint::Matches, "/v1/tournaments/{}/matches");
m
};
}
As you may see, the map item which is accessible by Endpoint::Matches key returns a string which needs to be formatted, however, I don't see a way of doing this.
I've tried to use format! macro but it needs string literals but not an object so it does not work. I tried to search the solution over the internet and rust std library but I was unable to find it. Is there any way to do this?
For clarification why format! does not work:
error: format argument must be a string literal.
--> src/lib.rs:249:31
|
249 | let address = format!(get_ep_address(Endpoint::Matches)?, id.0);
get_ep_address(Endpoint::Matches)? is not a string literal so it can't work.
I would also like to know how to format both &str and String types.

The format! macro expects a literal because it invokes compiler magic (format_args!) to check the format at compile and ensure that its arguments implement the necessary trait. For example {} requires that the argument implements Display, as described in Formatting traits.
You might be able to cobble something together by reaching to Formatter directly, but it means parsing the str yourself.
Note: Rust does not feature reflection, so checking whether a type implements a given trait at runtime is not easy...

Related

Why can I pass a parameter of &&str to a function requires &str? [duplicate]

This question already has answers here:
What are Rust's exact auto-dereferencing rules?
(4 answers)
Confusion over auto-dereferencing rules when using function
(1 answer)
Closed 4 years ago.
The following program works fine:
pub fn foo(_v: &str) -> bool {
false
}
fn main() {
let f = "hello world";
println!("{}", foo(&&&&f)); // note the number of & here
}
In fact it works on passing any number of &. How should I interpret what is going on ?
My rust version:
$ rustc --version
rustc 1.32.0-nightly (13dab66a6 2018-11-05)
From the Rust book:
Deref coercion is a convenience that Rust performs on arguments to
functions and methods. Deref coercion converts a reference to a type
that implements Deref into a reference to a type that Deref can
convert the original type into. Deref coercion happens automatically
when we pass a reference to a particular type’s value as an argument
to a function or method that doesn’t match the parameter type in the
function or method definition. A sequence of calls to the deref method
converts the type we provided into the type the parameter needs.
So basically, in function arguments the compiler will automatically remove any & written or implied until it gets to a type that can be passed to the function.
Because the compiler automatically dereferences the chain of references, you can imagine that it inserts as many * as necessary to get the right type:
foo(&&&f)
is converted to:
foo(&****(&&&f))
that leads to the right invocation:
foo(f)
The insertions of as many * as needed is actually performed by this blanket implementation of Deref trait:
impl<'a, T: ?Sized> Deref for &'a T {
type Target = T;
fn deref(&self) -> &T { *self }
}
Note: I've update my answer because in the original I used the term autoderef in the wrong way, see this post for details.

Program with multiple ampersand works fine [duplicate]

This question already has answers here:
What are Rust's exact auto-dereferencing rules?
(4 answers)
Confusion over auto-dereferencing rules when using function
(1 answer)
Closed 4 years ago.
The following program works fine:
pub fn foo(_v: &str) -> bool {
false
}
fn main() {
let f = "hello world";
println!("{}", foo(&&&&f)); // note the number of & here
}
In fact it works on passing any number of &. How should I interpret what is going on ?
My rust version:
$ rustc --version
rustc 1.32.0-nightly (13dab66a6 2018-11-05)
From the Rust book:
Deref coercion is a convenience that Rust performs on arguments to
functions and methods. Deref coercion converts a reference to a type
that implements Deref into a reference to a type that Deref can
convert the original type into. Deref coercion happens automatically
when we pass a reference to a particular type’s value as an argument
to a function or method that doesn’t match the parameter type in the
function or method definition. A sequence of calls to the deref method
converts the type we provided into the type the parameter needs.
So basically, in function arguments the compiler will automatically remove any & written or implied until it gets to a type that can be passed to the function.
Because the compiler automatically dereferences the chain of references, you can imagine that it inserts as many * as necessary to get the right type:
foo(&&&f)
is converted to:
foo(&****(&&&f))
that leads to the right invocation:
foo(f)
The insertions of as many * as needed is actually performed by this blanket implementation of Deref trait:
impl<'a, T: ?Sized> Deref for &'a T {
type Target = T;
fn deref(&self) -> &T { *self }
}
Note: I've update my answer because in the original I used the term autoderef in the wrong way, see this post for details.

About trait Index implement of Vector in Rust [duplicate]

This question already has answers here:
What is the return type of the indexing operation?
(2 answers)
Closed 4 years ago.
I check Index trait in doc and find return type of index() is &T.
Then I write this function to get value from vector:
fn get_value_test(a: usize, v: &Vec<i32>) -> i32 {
v[a]
}
My question is: why v[a] is i32 but &i32? Because i32 ...have a known size at compile time are stored entirely on the stack, so copies of the actual values are quick to make? (from here)
It looks like Rust have hidden rule to convert type in this situation?
There was a small misguidance here. Although the method prototype for Index<Idx> is fn index(&self, index: Idx) -> &T, the syntactical operator x[i] does dereference the output from that &T:
container[index] is actually syntactic sugar for *container.index(index) [...]. This allows nice things such as let value = v[index] if the type of value implements Copy.
So there you go. Your function is indeed returning a copy of the value from the vector, but not from an implicit conversion. If the original intent was to really retrieve a reference to that value, you would do &x[i].
See also:
Meaning of the ampersand '&' and star '*' symbols in Rust
Does Rust automatically dereference primitive type references?

Is there a `connect()` implementation for `Iterator<Item=Str>`? [duplicate]

This question already has answers here:
What's an idiomatic way to print an iterator separated by spaces in Rust?
(4 answers)
Closed 5 years ago.
Currently the SliceConcatExt seems to be very specifically crafted for slices or vectors of Strings, even though it arbitrarily constrains its use. That particular use-case is reflected in the trait name as well, after all, it is called SliceConcatExt for a reason.
Is there a more general connect() implementation which would take any Iterator over items supporting the Str trait ?.
If not, are there any plans to remedy this ?
Example
use std::iter::IntoIterator;
fn connected<S, I>(s: I) -> String
where S: Str,
I: IntoIterator<Item=S> {
// have
s.into_iter().collect::<Vec<S>>().connect(", ")
// want
// s.into_iter().connect(", ")
// error: type `<I as core::iter::IntoIterator>::IntoIter` does not implement any method in scope named `connect`
// tests/lang.rs:790 s.into_iter().connect(", ")
}
connected(&["foo", "bar"]);
One could possibly implement SliceConcatExt for any iterator with item type Str, but I have the suspicion that connect() currently is just unnecessarily specialized, which might be fixable until Rust beta.
Using rustc 1.0.0-nightly (522d09dfe 2015-02-19) (built 2015-02-19)
The closest solution I know of would be to use Itertools::intersperse:
#![feature(core)]
extern crate itertools;
use std::iter::IntoIterator;
use itertools::Itertools;
fn connected<'a, S, I>(s: I) -> String //'
where S: Str,
I: IntoIterator<Item=&'a S> //'
{
s.into_iter().map(|s| s.as_slice()).intersperse(", ").collect()
}
fn main() {
println!("{}", connected(&["foo", "bar"]));
}

How do I convert from an integer to a string?

I am unable to compile code that converts a type from an integer to a string. I'm running an example from the Rust for Rubyists tutorial which has various type conversions such as:
"Fizz".to_str() and num.to_str() (where num is an integer).
I think the majority (if not all) of these to_str() function calls have been deprecated. What is the current way to convert an integer to a string?
The errors I'm getting are:
error: type `&'static str` does not implement any method in scope named `to_str`
error: type `int` does not implement any method in scope named `to_str`
Use to_string() (running example here):
let x: u32 = 10;
let s: String = x.to_string();
println!("{}", s);
You're right; to_str() was renamed to to_string() before Rust 1.0 was released for consistency because an allocated string is now called String.
If you need to pass a string slice somewhere, you need to obtain a &str reference from String. This can be done using & and a deref coercion:
let ss: &str = &s; // specifying type is necessary for deref coercion to fire
let ss = &s[..]; // alternatively, use slicing syntax
The tutorial you linked to seems to be obsolete. If you're interested in strings in Rust, you can look through the strings chapter of The Rust Programming Language.

Resources