You know how you can create a new type by wrapping an existing type just because you want to avoid the Copy trait?! For example, you have bool
and you want a new type MyBool, you do struct MyBool(bool);
and then you can use that to avoid the Copy trait.
What I want to know is how do you do it(create a new type, that is) for an array type? eg. for the type of a
in let a = [0; 4];
which is [{integer}; 4]
, array of four integer elements. And can you do it for an array of a specific type X and of a specific len Y ? or, only for an array of type T (think generics) and with/without(?) a specific array length embedded in the new type ?
So, for bool
, the following code doesn't show any warnings/errors(even if you run cargo clippy
on it):
#![deny(clippy::all, clippy::pedantic, clippy::nursery, warnings, future_incompatible,
nonstandard_style, non_ascii_idents, clippy::restriction, rust_2018_compatibility,
rust_2021_compatibility, unused)]
#![allow(clippy::print_stdout, clippy::use_debug, clippy::missing_docs_in_private_items)]
#![allow(clippy::blanket_clippy_restriction_lints)] //workaround clippy
// might want to deny later:
//#![allow(clippy::default_numeric_fallback)] // might want to deny later!
//#![allow(clippy::dbg_macro)]
fn main() {
let mut has_spawned:bool=false;
//...
let handler=std::thread::spawn(move || {
println!("Before {has_spawned}!"); // false
has_spawned=true;
println!("Set {has_spawned}!"); // true
});
#[allow(clippy::unwrap_used)]
handler.join().unwrap();
println!("Current {has_spawned}!"); // false
}
But I want it to show me errors, thus, I use a new type for bool
, MyBool
:
#![deny(clippy::all, clippy::pedantic, clippy::nursery, warnings, future_incompatible,
nonstandard_style, non_ascii_idents, clippy::restriction, rust_2018_compatibility,
rust_2021_compatibility, unused)]
#![allow(clippy::print_stdout, clippy::use_debug, clippy::missing_docs_in_private_items)]
#![allow(clippy::blanket_clippy_restriction_lints)] //workaround clippy
#[derive(Debug)]
struct MyBool(bool);
fn main() {
let mut my_has_spawned:MyBool=MyBool(false);
//...
let handler=std::thread::spawn(move || {
println!("Before {my_has_spawned:?}!"); //MyBool(false)
//my_has_spawned=MyBool(true);
my_has_spawned.0=true;
println!("Set {my_has_spawned:?}!"); // MyBool(true)
});
#[allow(clippy::unwrap_used)]
handler.join().unwrap();
println!("Current {my_has_spawned:#?}!"); // value borrowed here after move, XXX: this is what
// I wanted!
}
and now it shows me exactly what I want to see:
error[E0382]: borrow of moved value: `my_has_spawned`
--> /home/user/sandbox/rust/copy_trait/gotcha1/copy_trait_thread_newtype/src/main.rs:20:24
|
10 | let mut my_has_spawned:MyBool=MyBool(false);
| ------------------ move occurs because `my_has_spawned` has type `MyBool`, which does not implement the `Copy` trait
11 | //...
12 | let handler=std::thread::spawn(move || {
| ------- value moved into closure here
13 | println!("Before {my_has_spawned:?}!"); //MyBool(false)
| -------------- variable moved due to use in closure
...
20 | println!("Current {my_has_spawned:#?}!"); // value borrowed here after move, XXX: this is what
| -------------------^^^^^^^^^^^^^^-------
| | |
| | value borrowed here after move
| in this macro invocation (#1)
|
::: /usr/lib/rust/1.64.0/lib/rustlib/src/rust/library/std/src/macros.rs:101:1
|
101 | macro_rules! println {
| -------------------- in this expansion of `println!` (#1)
...
106 | $crate::io::_print($crate::format_args_nl!($($arg)*));
| --------------------------------- in this macro invocation (#2)
|
::: /usr/lib/rust/1.64.0/lib/rustlib/src/rust/library/core/src/macros/mod.rs:906:5
|
906 | macro_rules! format_args_nl {
| --------------------------- in this expansion of `$crate::format_args_nl!` (#2)
For more information about this error, try `rustc --explain E0382`.
error: could not compile `copy_trait_thread_newtype` due to previous error
Similarly to the above, I want to use the new type for this array program that yields no warnings or errors(even through cargo clippy
):
#![deny(clippy::all, clippy::pedantic, clippy::nursery, warnings, future_incompatible,
nonstandard_style, non_ascii_idents, clippy::restriction, rust_2018_compatibility,
rust_2021_compatibility, unused)]
#![allow(clippy::print_stdout, clippy::use_debug, clippy::missing_docs_in_private_items)]
#![allow(clippy::blanket_clippy_restriction_lints)] //workaround clippy
// might want to deny later:
#![allow(clippy::default_numeric_fallback)] // might want to deny later!
#![allow(clippy::dbg_macro)]
//src: https://users.rust-lang.org/t/rust-book-suggestion-add-a-section-regarding-copy-vs-move/1549/2
fn foo(mut x: [i32; 4]) {
println!("x(before) = {:?}", x);
x = [1, 2, 3, 4];
println!("x(after) = {:?}", x);
}
//src: https://stackoverflow.com/a/58119924/19999437
fn print_type_of<T>(_: &T) {
//println!("{}", std::any::type_name::<T>());
println!("{}", core::any::type_name::<T>());
}
//struct MyArray(array); //TODO: how?
fn main() {
let a = [0; 4];
//a.something();//method not found in `[{integer}; 4]`
//a=1;//so this is an array
//dbg!(a);
println!("{:#?}", print_type_of(&a)); // i32
foo(a); //sneakily copied! thanks Copy trait!
println!("a = {:?}", a);//unchanged, doh! but since it was just copied above, can use it here
//without errors!
}
output of that is:
[i32; 4]
()
x(before) = [0, 0, 0, 0]
x(after) = [1, 2, 3, 4]
a = [0, 0, 0, 0]
So you see, I want a new type in order to avoid the copying of a
when foo(a);
is called, so that the computer/compiler can keep track of when I would introduce such easy bugs in my code, by error-ing instead, which happens only when a
is moved(instead of just copied) when foo(a);
is called.
Side note: do you think that this clippy lint https://github.com/rust-lang/rust-clippy/issues/9061 if implemented would be able to warn/err for me in such cases? That would be cool!
Personally I dislike the Copy trait for the only reason that it bypasses the borrow checker and thus allows you to write code that introduces subtle bugs. ie. you can keep using the stale value of the "moved"(copied) variable and the compiler won't complain.
Even if there are better ways to do what I want, please also do answer the title question: how I can wrap the array type in my own new type?