This question already has answers here:
Why is it discouraged to accept a reference &String, &Vec, or &Box as a function argument?
(4 answers)
Closed 12 months ago.
When I do exercise in rustlings, I found that exercise:
pub fn capitalize_words_string(words: &[&str]) -> String {}
i try to change function to
pub fn capitalize_words_string(words: &Vec<&str>) -> String {}
It also works properly, So my question is what is different between &[&str] with &Vec<&str> in rust? Thanks!
Let's substitute the inner &str with T. Then &[T] is a slice of T and &Vec<T> is a reference to a vector of T.
When a function is defined to accept a &[T], you can also pass a &Vec<T>. Another very common case is to declare a parameter as &str, as that allows you to directly pass, for example &String. This is known as Deref coercion.
Related
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.
This question already has an answer here:
What is the relation between auto-dereferencing and deref coercion?
(1 answer)
Closed 3 years ago.
Given a rust option:
let mut x = Some(3);
Why can I directly call x.as_mut()? As I can see from the doc, as_mut is defined as:
pub fn as_mut(&mut self) -> Option<&mut T> Converts from &mut
Option to Option<&mut T>.
which expects the first parameter to be &mut self, i.e. &mut Option<T>. Shouldn't I use (&mut x).as_mut() instead?
Here Rust's . operator does what you mean and implicitly borrows the variable. If it didn't, working with non-borrowed values would be annoying, because a value declared as e.g. let mut v = vec![1, 2, 3] couldn't be manipulated with e.g. v.push(4) without writing (&mut v).push(4). The same would apply to fields, so if a struct contained a vector, you'd be unable to call container.vec.push(element) without explicitly borrowing container.vec, even if container itself was itself a mutable reference.
To prevent such noise C has two operators for field access, . and ->, where the latter automatically dereferences. Rust's . intentionally goes ahead and does the borrowing or dereferencing needed for the method call to work.
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.
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?
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"]));
}