To print simple struct or enum, derived from Debug or explicit fmt::Display implementation? [closed] - rust

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed last month.
Improve this question
I have a simple enum or struct and want to print. We know that being derived from Debug automatically enables a quick printing without explicit an implementation of fmt::Display. But you can still implement Display for printing it.
#[derive(Clone, Copy, PartialEq)]
pub enum MyDataType {
INVALID = 0,
TYPE1 = 1,
TYPE2 = 2,
}
let my_type: MyDataType = ...;
// This won't compile.
println!("{my_type}");
|
10 | println!("{my_type}");
| ^^^^^^^ `MyDataType` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `MyDataType`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
So, there're two approaches to make it work:
// Simply using Debug
#[derive(Debug)]
// Or, have your own Display implementation
impl fmt::Display for MyDataType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MyDataType::INVALID => write!(f, "INVALID"),
MyDataType::TYPE1 => write!(f, "TYPE1"),
MyDataType::TYPE2 => write!(f, "TYPE2"),
}
}
}
What are the tradeoffs between these two approaches? Which one do you prefer?

Your question seems to imply there's only two options, derive Debug or manually implement Display, which is not the case at all, you can do both (or neither) and for different reasons. Debug and Display are different traits for different purposes; Debug is developer-centric while Display is user-centric.
If the derived implementation is good enough for developers, great! You can use that! If not, you can implement it manually. And if that is also good enough for users, great! You can defer to the Debug implementation when implementing Display as #cdhowie suggested in the comments. If not, you can implement that manually as well.
I don't see any "tradeoffs" to really consider here. If the derived implementation isn't what you want, then don't use it. Its up to you what you need and how it should be formatted.

Related

how to structure rust code to have Vec<Box<dyn FooTrait>> with ability calling BarTrait [duplicate]

This question already has an answer here:
Can I get a trait object of a multi-trait instance without using a generic type?
(1 answer)
Closed 2 years ago.
TL;DR;
struc: TheirPoint, TheirLine
trait: TheirShadow, MySpecialShadow
TheirShadow for TheirPoint
TheirShadow for TheirLine
MySpecialShadow for TheirPoint
MySpecialShadow for TheirLine
let vec_shapes: Vec<Box<dyn TheirShadow>> = vec![Box::new(point), Box::new(line)];
Problem:
for shape in vec_shapes {
shape.myspecialshadow_function()
//doesnt work - what can be done? Downcast? - but how to handle different types?
}
Long version:
Playground
I'm working with a lib <TheirThings> and use that in <MyCode>.
Specifically, I use different of their Shapes (TheirPoint, TheirLine) which have all a common
output: TheirOutput which is an enum
function: cast_shadow provided by Trait TheirShadow, which returns TheirOutput
I have a Vec<Box<dyn TheirShadow>>
let vec_shapes: Vec<Box<dyn TheirShadow<Output=TheirOutput>>> = vec![Box::new(p), Box::new(l)];
I've created a Trait MySpecialShadow, having a function special_shadow which I implement individually for TheirPoint, TheirLine, and I struggle being able to call it during a loop over vec_shapes.
I tried the following without success
let vec_shapes: Vec<Box<dyn TheirShadow<Output=TheirOutput, MySpecialShadow>>> = vec![Box::new(p), Box::new(l)];
Do you have a recommendation how to structure the code so that a mixed vec based on dyn Trait enables call ability to other traits? Downcasting? How would that look like for a mixed vec?
Thanks for ideas!
Based on the hint #pretzelhammer commented, I've been able to end up with this playground, which works even if not the same struct gets implemented for the different traits, but the struct with trait 1 wrapped in struct with trait 2.
I'm still not sure, if thats the smartest way to go forward, so if there are concepts out there to better achieve such a solution, please share!

Cant Set Struct Property to Enum Rust [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I have a structure textApp with field mode, which has a type of a Mode:
pub struct textApp{
mode: Mode,
}
pub enum Mode {
Single,
Multiple,
}
I initialize a new instance of the textApp structure as myTextApp, and I have a button then when clicked I want it to change the value of myTextApp's .mode field to Mode::Single:
fn main(){
let mut myTextApp = textApp{
mode: Mode::Multiple,
};
singleModeBut.set_callback(move||{
let newMode: Mode = Mode::Single;
textApp.mode = newMode;
//throws an error
});
}
but this gives me the error:
error[E0423]: expected value, found struct `textApp`
| textApp.mode = newModeSet;
| ^^^^^^^-----
| |
| help: use the path separator to refer to an item: `textApp::mode`
Why can't I set this struct field to Mode::Single?
Your struct's instance name is myTextApp. You are trying to set using struct's name which doesn't make sense.
Changing,
textApp.mode = newMode;
to
myTextApp.mode = newMode;
will fix it.
Playground
Also, it's a good idea to follow rust style guidelines that ask you to use snake case for identifier names and upper camel case for type names. That will help you avoid such errors.

Why is this pattern match necessary? [duplicate]

This question already has an answer here:
Pattern matching on same arm with different types
(1 answer)
Closed 3 years ago.
I am reading this and is like some lines of code are not necessary.
For example in the example below, is the match really useful? Why is it needed? Seems like repetitive code? Maybe the compiler resolve this and it is written only for expressiveness?
#[stable(feature = "sockaddr_setters", since = "1.9.0")]
pub fn set_port(&mut self, new_port: u16) {
match *self {
SocketAddr::V4(ref mut a) => a.set_port(new_port),
SocketAddr::V6(ref mut a) => a.set_port(new_port),
}
}
match is required to access the inner value. A SocketAddr can contain either a SocketAddrV4 or a SocketAddrV6, so you need to handle both possibilities.

Are there any nice cases where we should use `unwrap`? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
Since using unwrap may be problematic because it crashes in the error scenario, it may be considered as dangerous usage.
What if I am hundred percent sure that it will not crash, like in the following scenarios:
if option.is_some() {
let value = option.unwrap();
}
if result.is_ok() {
let result_value = result.unwrap();
}
Since we already checked the Result and Option there will be no crash with the unwrap() usage. However, we could have used match or if let. In my opinion, either match or if let usage is more elegant.
Let's focus on Result; I'll go back to Option at the end.
The purpose of Result is to signal a result which may succeed or fail with an error. As such, any use of it should fall into this category. Let's ignore the cases where a crate returns Result for impossible-to-fail operations.
By doing what you are doing (checking if result.is_ok() then extracting the value), you're effectively doing the same thing twice. The first time, you're inspecting the content of the Result, and the second, you're checking and extracting unsafely.
This could indeed have been done with a match or map, and both would have been more idiomatic than an if. Consider this case for a moment:
You have an object implementing the following trait:
use std::io::{Error, ErrorKind};
trait Worker {
fn hours_left(&self) -> Result<u8, Error>;
fn allocate_hours(&mut self, hours: u8) -> Result<u8, Error>;
}
We're going to assume hours_left() does exactly what it says on the tin. We'll also assume we have a mutable borrow of Worker. Let's implement allocate_hours().
In order to do so, we'll obviously need to check if our worker has extra hours left over to allocate. You could write it similar to yours:
fn allocate_hours(&mut self, hours: u8) {
let hours_left = self.hours_left();
if (hours_left.is_ok()) {
let remaining_hours = hours_left.unwrap();
if (remaining_hours < hours) {
return Err(Error::new(ErrorKind::NotFound, "Not enough hours left"));
}
// Do the actual operation and return
} else {
return hours_left;
}
}
However, this implementation is both clunky and inefficient. We can simplify this by avoiding unwrap and if statements altogether.
fn allocate_hours(&mut self, hours: u8) -> Result<u8, Error> {
self.hours_left()
.and_then(|hours_left| {
// We are certain that our worker is actually there to receive hours
// but we are not sure if he has enough hours. Check.
match hours_left {
x if x >= hours => Ok(x),
_ => Err(Error::new(ErrorKind::NotFound, "Not enough hours")),
}
})
.map(|hours_left| {
// At this point we are sure the worker has enough hours.
// Do the operations
})
}
We've killed multiple birds with one stone here. We've made our code more readable, easier to follow and we've removed a whole bunch of repeated operations. This is also beginning to look like Rust and less like PHP ;-)
Option is similar and supports the same operations. If you want to process the content of either Option or Result and branch accordingly, and you're using unwrap, there are so many pitfalls you'll inevitably fall into when you forget you unwrapped something.
There are genuine cases where your program should barf out. For those, consider expect(&str) as opposed to unwrap()
In many, many cases you can avoid unwrap and others by more elegant means. However, I think there are situations where it is the correct solution to unwrap.
For example, many methods in Iterator return an Option. Let us assume that you have a nonempty slice (known to be nonempty by invariants) and you want to obtain the maximum, you could do the following:
assert!(!slice.empty()); // known to be nonempty by invariants
do_stuff_with_maximum(slice.iter().max().unwrap());
There are probably several opinions regarding this, but I would argue that using unwrap in the above scenario is perfectly fine - in the presence of the preceeding assert!.
My guideline is: If the parameters I am dealing with are all coming from my own code, not interfacing with 3rd party code, possibly assert!ing invariants, I am fine with unwrap. As soon as I am the slightest bit unsure, I resort to if, match, map and others.
Note that there is also expect which is basically an "unwrap with a comment printed in the error case". However, I have found this to be not-really-ergonomic. Moreover, I found the backtraces a bit hard to read if unwrap fails. Thus, I currently use a macro verify! whose sole argument is an Option or Result and that checks that the value is unwrapable. It is implemented like this:
pub trait TVerifiableByVerifyMacro {
fn is_verify_true(&self) -> bool;
}
impl<T> TVerifiableByVerifyMacro for Option<T> {
fn is_verify_true(&self) -> bool {
self.is_some()
}
}
impl<TOk, TErr> TVerifiableByVerifyMacro for Result<TOk, TErr> {
fn is_verify_true(&self) -> bool {
self.is_ok()
}
}
macro_rules! verify {($e: expr) => {{
let e = $e;
assert!(e.is_verify_true(), "verify!({}): {:?}", stringify!($e), e)
e
}}}
Using this macro, the aforementioned example could be written as:
assert!(!slice.empty()); // known to be nonempty by invariants
do_stuff_with_maximum(verify!(slice.iter().max()).unwrap());
If I can't unwrap the value, I get an error message mentioning slice.iter().max(), so that I can search my codebase quickly for the place where the error occurs. (Which is - in my experience - faster than looking through the backtrace for the origin of the error.)

Is passing an iterator to a function as an argument an anti-pattern? [duplicate]

This question already has answers here:
How to write a Rust function that takes an iterator?
(3 answers)
Closed 5 years ago.
Say I have a string, from which I make an iterator (cycle-able, peek-able) over its chars:
let hello = "hello";
let mut iterator = hello.chars().cycle().peekable;
I wanted to figure out what the type of iterator is, so I purposefully introduced an error:
let mut iterator: usize = hello.chars().cycle().peekable;
The compiler then informed me that the type of the right hand side is:
std::iter::Peekable<std::iter::Cycle<std::str::Chars<'_>>>
Wow, that's a mouthful. If I define a function like so:
fn foobar(x: std::iter::Peekable<std::iter::Cycle<std::str::Chars<'_>>>){
// snip
}
I get an error like this:
error: underscore lifetimes are unstable (see issue #44524)
So, if I want to pass an iterator to a function, how should I do so? Or, is this something I should avoid?
Ok so there are multiple aspects to this questions:
First of, you can avoid the compiler error by giving it an explicit lifetime:
fn foobar<'a>(mut x: std::iter::Peekable<std::iter::Cycle<std::str::Chars<'a>>>){
To the he second question, whether this is idiomatic or not, i'd say no, avoid this specific approach.
You can only pass in this specific Iterator chain - something else is not possible. But most of the times, your algorithm isn't interested in the specific combination, rather than the functionality to "produce" chars. Use generics orimpl Trait instead (if you have access to nightly rust).
Impl Trait is a feature, which allows hiding the specific type used. This specific feature, accepting impl traits in argument position landed as of a few days ago, at the time of writing. I made this quick sketch for demonstration purposes, playground link
#![feature(universal_impl_trait)]
fn main() {
foo("hello".chars());
foo("hello".chars().rev());
}
fn foo(x: impl Iterator<Item=char>) {
let text: String = x.collect();
println!("{}", &text)
}
Edit: You can use generics as well, see comments from nullqube and stefan

Resources