In general, I prefer to write initializer functions with descriptive names. However, for some structs, there is an obvious default initializer function. The standard Rust name for such a function is new, placed in the impl block for the struct. However, today I realized that I can give a function the same name as a struct, and thought this would be a good way to implement the obvious initializer function. For example:
#[derive(Debug, Clone, Copy)]
struct Pair<T, U> {
first: T,
second: U,
}
#[allow(non_snake_case)]
fn Pair<T, U>(first: T, second: U) -> Pair<T, U> {
Pair::<T, U> {
first: first,
second: second,
}
}
fn main(){
let x = Pair(1, 2);
println!("{:?}", x);
}
This is, in my opinion, much more appealing than this:
let x = Pair::new(1, 2);
However, I've never seen anyone else do this, and my question is simply if there are any problems with this approach. Are there, for example, ambiguities which it can cause which will not be there with the new implementation?
If you want to use Pair(T, U) then you should consider using a tuple struct instead:
#[derive(Debug, Clone, Copy)]
struct Pair<T, U>(T, U);
fn main(){
let x = Pair(1, 2);
println!("{:?}", x);
println!("{:?}, {:?}", (x.0, x.1));
}
Or, y’know, just a tuple ((T, U)). But I presume that Pair is not your actual use case.
There was a time when having identically named functions was the convention for default constructors; this convention fell out of favour as time went by. It is considered bad form nowadays, probably mostly for consistency. If you have a tuple struct (or variant) Pair(T, U), then you can use Pair(first, last) in a pattern, but if you have Pair { first: T, last: U } then you would need to use something more like Pair { first, last } in a pattern, and so your Pair(first, last) function would be inconsistent with the pattern. It is generally felt, thus, that these type of camel-case functions should be reserved solely for tuple structs and tuple variants, where it can be known that it is genuinely reflecting what is contained in the data structure with no further processing or magic.
Related
I have the following:
enum SomeType {
VariantA(String),
VariantB(String, i32),
}
fn transform(x: SomeType) -> SomeType {
// very complicated transformation, reusing parts of x in order to produce result:
match x {
SomeType::VariantA(s) => SomeType::VariantB(s, 0),
SomeType::VariantB(s, i) => SomeType::VariantB(s, 2 * i),
}
}
fn main() {
let mut data = vec![
SomeType::VariantA("hello".to_string()),
SomeType::VariantA("bye".to_string()),
SomeType::VariantB("asdf".to_string(), 34),
];
}
I would now like to call transform on each element of data and store the resulting value back in data. I could do something like data.into_iter().map(transform).collect(), but this will allocate a new Vec. Is there a way to do this in-place, reusing the allocated memory of data? There once was Vec::map_in_place in Rust but it has been removed some time ago.
As a work-around, I've added a Dummy variant to SomeType and then do the following:
for x in &mut data {
let original = ::std::mem::replace(x, SomeType::Dummy);
*x = transform(original);
}
This does not feel right, and I have to deal with SomeType::Dummy everywhere else in the code, although it should never be visible outside of this loop. Is there a better way of doing this?
Your first problem is not map, it's transform.
transform takes ownership of its argument, while Vec has ownership of its arguments. Either one has to give, and poking a hole in the Vec would be a bad idea: what if transform panics?
The best fix, thus, is to change the signature of transform to:
fn transform(x: &mut SomeType) { ... }
then you can just do:
for x in &mut data { transform(x) }
Other solutions will be clunky, as they will need to deal with the fact that transform might panic.
No, it is not possible in general because the size of each element might change as the mapping is performed (fn transform(u8) -> u32).
Even when the sizes are the same, it's non-trivial.
In this case, you don't need to create a Dummy variant because creating an empty String is cheap; only 3 pointer-sized values and no heap allocation:
impl SomeType {
fn transform(&mut self) {
use SomeType::*;
let old = std::mem::replace(self, VariantA(String::new()));
// Note this line for the detailed explanation
*self = match old {
VariantA(s) => VariantB(s, 0),
VariantB(s, i) => VariantB(s, 2 * i),
};
}
}
for x in &mut data {
x.transform();
}
An alternate implementation that just replaces the String:
impl SomeType {
fn transform(&mut self) {
use SomeType::*;
*self = match self {
VariantA(s) => {
let s = std::mem::replace(s, String::new());
VariantB(s, 0)
}
VariantB(s, i) => {
let s = std::mem::replace(s, String::new());
VariantB(s, 2 * *i)
}
};
}
}
In general, yes, you have to create some dummy value to do this generically and with safe code. Many times, you can wrap your whole element in Option and call Option::take to achieve the same effect .
See also:
Change enum variant while moving the field to the new variant
Why is it so complicated?
See this proposed and now-closed RFC for lots of related discussion. My understanding of that RFC (and the complexities behind it) is that there's an time period where your value would have an undefined value, which is not safe. If a panic were to happen at that exact second, then when your value is dropped, you might trigger undefined behavior, a bad thing.
If your code were to panic at the commented line, then the value of self is a concrete, known value. If it were some unknown value, dropping that string would try to drop that unknown value, and we are back in C. This is the purpose of the Dummy value - to always have a known-good value stored.
You even hinted at this (emphasis mine):
I have to deal with SomeType::Dummy everywhere else in the code, although it should never be visible outside of this loop
That "should" is the problem. During a panic, that dummy value is visible.
See also:
How can I swap in a new value for a field in a mutable reference to a structure?
Temporarily move out of borrowed content
How do I move out of a struct field that is an Option?
The now-removed implementation of Vec::map_in_place spans almost 175 lines of code, most of having to deal with unsafe code and reasoning why it is actually safe! Some crates have re-implemented this concept and attempted to make it safe; you can see an example in Sebastian Redl's answer.
You can write a map_in_place in terms of the take_mut or replace_with crates:
fn map_in_place<T, F>(v: &mut [T], f: F)
where
F: Fn(T) -> T,
{
for e in v {
take_mut::take(e, f);
}
}
However, if this panics in the supplied function, the program aborts completely; you cannot recover from the panic.
Alternatively, you could supply a placeholder element that sits in the empty spot while the inner function executes:
use std::mem;
fn map_in_place_with_placeholder<T, F>(v: &mut [T], f: F, mut placeholder: T)
where
F: Fn(T) -> T,
{
for e in v {
let mut tmp = mem::replace(e, placeholder);
tmp = f(tmp);
placeholder = mem::replace(e, tmp);
}
}
If this panics, the placeholder you supplied will sit in the panicked slot.
Finally, you could produce the placeholder on-demand; basically replace take_mut::take with take_mut::take_or_recover in the first version.
I am working through the Rust book, namely the minigrep project. There I came across the following snippet:
fn main() {
let args: Vec<String> = env::args().collect();
let (query, filename) = parse_config(&args);
// --snip--
}
fn parse_config(args: &[String]) -> (&str, &str) {
let query = &args[1];
let filename = &args[2];
(query, filename)
}
The confusing piece for me is args: &[String]. If I replace it with args: &Vec<String>, it also works. My guess is that &[String] is a more general type annotation that matches not only &Vec<String>, but also some other types. Is that correct? If so, what other types are matched by [T]?
Generally speaking, [T] is a contiguous sequence and &[T] is a slice.
The reason why the compiler allows &[String] instead of &Vec<String> is that Vec<T> dereferences to [T]. This is called Deref coercion. It can be said that the former notation (in function parameters) is more general; it is also the preferred one. Further details about automatic dereferencing rules can be found in this question.
fn count_spaces(text: Vec<u8>) -> usize {
text.split(|c| c == 32u8).count()
}
The above function does not compile, and gives the following error on the comparison:
trait `&u8: std::cmp::PartialEq` not satisfied
I read this as: "c is a borrowed byte and cannot be compared to a regular byte", but I must be reading this wrong.
What would be the appropriate way to split a Vec<u8> on specific values?
I do realize that there are options when reading files, like splitting a BufReader or I could convert the vector to a string and use str::split. I might go with such a solution (passing in a BufReader instead of a Vec<u8>), but right now I'm just playing around, testing stuff and want to know what I'm doing wrong.
The code
You are actually reading it right: c is indeed a borrowed byte and cannot be compared to a regular byte. Try using any of the functions below instead:
fn count_spaces(text: Vec<u8>) -> usize {
text.split(|&c| c == 32u8).count()
}
fn count_spaces(text: Vec<u8>) -> usize {
text.split(|c| *c == 32u8).count()
}
The first one uses pattern matching on the parameter (&c) to dereference it, while the second one uses the dereference operator (*).
Why is c a &u8 instead of a u8?
If you take a look at the split method on the docs, you will see that the closure parameter is a borrow of the data in Vec. In this case, it means that the parameter will be &u8 instead of u8 (so in your code you are actually comparing &u8 to u8, which Rust doesn't like).
In order to understand why the closure takes the parameter by borrow and not by value, consider what would happen if the parameter was taken by value. In the case of Vec<u8>, there would be no problem since u8 implements Copy. However, in the case of a a Vec<String>, each String would be moved into the closure and destroyed!
The following is the Deref example from The Rust Programming Language except I've added another assertion.
Why does the assert_eq with the deref also equal 'a'? Why do I need a * once I've manually called deref?
use std::ops::Deref;
struct DerefExample<T> {
value: T,
}
impl<T> Deref for DerefExample<T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
fn main() {
let x = DerefExample { value: 'a' };
assert_eq!('a', *x.deref()); // this is true
// assert_eq!('a', x.deref()); // this is a compile error
assert_eq!('a', *x); // this is also true
println!("ok");
}
If I uncomment the line, I get this error:
error[E0308]: mismatched types
--> src/main.rs:18:5
|
18 | assert_eq!('a', x.deref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected char, found &char
|
= note: expected type `char`
found type `&char`
= help: here are some functions which might fulfill your needs:
- .to_ascii_lowercase()
- .to_ascii_uppercase()
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
First, let's spell out the generic types for your specific example: 'a' is char, so we have:
impl Deref for DerefExample<char> {
type Target = char;
fn deref(&self) -> &char {
&self.value
}
}
Notably, the return type of deref is a reference to a char. Thus it shouldn't be surprising that, when you use just x.deref(), the result is a &char rather than a char. Remember, at that point deref is just another normal method — it's just implicitly invoked as part of some language-provided special syntax. *x, for example, will call deref and dereference the result, when applicable. x.char_method() and fn_taking_char(&x) will also call deref some number of times and then do something further with the result.
Why does deref return a reference to begin with, you ask? Isn't that circular? Well, no, it isn't circular: it reduces library-defined smart pointers to the built-in type &T which the compiler already knows how to dereference. By returning a reference instead of a value, you avoid a copy/move (which may not always be possible!) and allow &*x (or &x when it's coerced) to refer to the actual char that DerefExample holds rather than a temporary copy.
See also:
Why is the return type of Deref::deref itself a reference?
I have a program that more or less looks like this
struct Test<T> {
vec: Vec<T>
}
impl<T> Test<T> {
fn get_first(&self) -> &T {
&self.vec[0]
}
fn do_something_with_x(&self, x: T) {
// Irrelevant
}
}
fn main() {
let t = Test { vec: vec![1i32, 2, 3] };
let x = t.get_first();
t.do_something_with_x(*x);
}
Basically, we call a method on the struct Test that borrows some value. Then we call another method on the same struct, passing the previously obtained value.
This example works perfectly fine. Now, when we make the content of main generic, it doesn't work anymore.
fn generic_main<T>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(*x);
}
Then I get the following error:
error: cannot move out of borrowed content
src/main.rs:14 let raw_x = *x;
I'm not completely sure why this is happening. Can someone explain to me why Test<i32> isn't borrowed when calling get_first while Test<T> is?
The short answer is that i32 implements the Copy trait, but T does not. If you use fn generic_main<T: Copy>(t: Test<T>), then your immediate problem is fixed.
The longer answer is that Copy is a special trait which means values can be copied by simply copying bits. Types like i32 implement Copy. Types like String do not implement Copy because, for example, it requires a heap allocation. If you copied a String just by copying bits, you'd end up with two String values pointing to the same chunk of memory. That would not be good (it's unsafe!).
Therefore, giving your T a Copy bound is quite restrictive. A less restrictive bound would be T: Clone. The Clone trait is similar to Copy (in that it copies values), but it's usually done by more than just "copying bits." For example, the String type will implement Clone by creating a new heap allocation for the underlying memory.
This requires you to change how your generic_main is written:
fn generic_main<T: Clone>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(x.clone());
}
Alternatively, if you don't want to have either the Clone or Copy bounds, then you could change your do_something_with_x method to take a reference to T rather than an owned T:
impl<T> Test<T> {
// other methods elided
fn do_something_with_x(&self, x: &T) {
// Irrelevant
}
}
And your generic_main stays mostly the same, except you don't dereference x:
fn generic_main<T>(t: Test<T>) {
let x = t.get_first();
t.do_something_with_x(x);
}
You can read more about Copy in the docs. There are some nice examples, including how to implement Copy for your own types.