I'm trying to add subcommands to my CLI tool in rust, using the clap library. When I copy the subcommand example from the docs
#[derive(clap::Parser)]
struct Args {
#[command(subcommand)]
action: Action,
}
#[derive(clap::Subcommand)]
enum Action {
Add,
Remove,
}
I get the following error:
error[E0277]: the trait bound `Action: FromStr` is not satisfied
| action: Action,
| ^^^^^^ the trait `FromStr` is not implemented for `Action`
Is the example from the docs broken?
Related
I'm trying to implement the trait diesel::Insertable<table in Rust.
In mail.rs
diesel::insert_into(mailing_list).values(
email // This is a String
).execute(connection);
This is because the following code results in this error:
error[E0277]: the trait bound `std::string::String: diesel::Insertable<table>` is not satisfied
--> src/mail.rs:18:10
|
17 | diesel::insert_into(mailing_list).values(
| ------ required by a bound introduced by this call
18 | email
| ^^^^^ the trait `diesel::Insertable<table>` is not implemented for `std::string::String`
Looking a bit more at the documentation from Diesel, I believe that I should make myself a struct that derives Insertable
In models.rs
#[derive(Insertable)]
pub struct NewSubscriber {
pub email: String
}
But then I get
but im getting this error
error[E0433]: failed to resolve: use of undeclared crate or module `new_subscribers`
--> src/models.rs:13:12
|
13 | pub struct NewSubscriber {
| ^^^^^^^^^^^^^ use of undeclared crate or module `new_subscribers`
I'm so confused why the compiler says it can't find a crate or module with a struct that I'm trying to define.
From the documentation on the Insertable derive macro:
To implement Insertable this derive needs to know the corresponding table type. By default it uses the snake_case type name with an added s from the current scope. It is possible to change this default by using #[diesel(table_name = something)].
So you need to define a "new_subscribers" table using table!. If you've already done so make sure you import it into scope, or if you already have a table and its in scope but with a different name, add the above attribute.
Judging by your insert statement, it looks like the table you're inserting into is mailing_list so use the last option:
#[derive(Insertable)]
#[diesel(table_name = mailing_list)]
pub struct NewSubscriber {
pub email: String
}
so i have got two files main.rs and utils.rs
I implemented StringUtils method on utils.rs but when I try to use the method in main.rs
it gives me this error
error[E0599]: no method named `slice` found for reference `&str` in the current scope
--> src\main.rs:89:50
|
89 | let text: String = self.inner.clone().as_str().slice(self.start, self.current);
| ^^^^^ method not found in `&str`
|
= help: items from traits can only be used if the trait is implemented and in scope
note: `StringUtils` defines an item `slice`, perhaps you need to implement it
--> src\util.rs:25:1
|
25 | trait StringUtils {
| ^^^^^^^^^^^^^^^^^
// main.rs
mod utils;
use utils::*;
...
fn add_token0(&mut self, token_type: TokenType) {
let text: String = self.inner.clone().as_str().slice(self.start, self.current);
// error: no method named `slice` found for reference `&str` in the current scope
}
...
but I implemented it already on utils.rs
// utils.rs
...
trait StringUtils {
...
fn slice(&self, range: impl RangeBounds<usize>) -> &str;
...
}
impl StringUtils for str {
...
fn slice(&self, range: impl RangeBounds<usize>) -> &str {
...
}
...
}
...
why doesn't my implementation work, and is there any way to solve it or I can only implement StringUtils on main.rs?
A substantively equivalent example appears in the section Paths for Referring to an Item in the Module Tree in The Rust Programming Language (which if you haven't read, I would suggest).
The short version is that any item (e.g., trait, function definition) within a module that you would like to be visible to other modules should have some variant of a pub visibility modifier. In your instant example, this manifests as needing to make the StringUtils trait pub (or some other variant exposing it to the containing module).
In fact, if you attempt to import StringUtils directly, via use utils::StringUtils instead of a glob import, you'd get the following error message:
error[E0603]: trait `StringUtils` is private
--> src/lib.rs:7:12
|
7 | use utils::StringUtils;
| ^^^^^^^^^^^ private trait
|
note: the trait `StringUtils` is defined here
--> src/lib.rs:19:5
|
19 | trait StringUtils {
| ^^^^^^^^^^^^^^^^^
Which would link to this explanation of one way to fix it. So if we do pub trait StringUtils { ... } instead, there are no issues relating to using the trait.
You would still have the issue #trentcl mentions concerning the incorrect number of parameters to slice, and I presume self.start..self.current (or the inclusive version) should be the range passed instead.
Finally, there is an error relating to your type annotation of text as StringUtils::slice would return &str, not String. Depending on what you want, you should either change the trait and its implementations or take a look at ways to go between &str and String and the differences between them.
(playground).
You may want to have a more restrictive visibility modifier, like pub(crate) or pub(super) which restrict visibility to the containing crate or the containing module, respectively.
A more exhaustive explanation of this can be found in the relevant section in The Rust Reference.
I'm creating a macro that parses a user-generated trait and creates helper functions for it. I have type restrictions on some of the arguments used, so I've been following the example in the quote crate to generate some code that'll throw a compilation error if a trait isn't implemented. It's not perfect but it gets the job done:
struct _AssertSync where #ty: Sync;
I'd also like to be able to check if the trait has Hash as a supertrait. If I follow the same pattern, I get an error:
struct _AssertHash where dyn #tr: Hash;
A complete example:
use std::hash::Hash;
trait BadBoi {}
trait GoodBoi: Hash {}
struct _AssertHash
where
dyn GoodBoi: Hash;
error[E0038]: the trait `GoodBoi` cannot be made into an object
--> src/lib.rs:6:39
|
4 | trait GoodBoi: Hash {}
| ------- this trait cannot be made into an object...
5 |
6 | struct _AssertHash where dyn GoodBoi: Hash;
| ^^^^ the trait `GoodBoi` cannot be made into an object
|
= help: consider moving `hash` to another trait
Is there any way for me to get around this?
You can check a supertrait-relationship by using two functions, for example:
fn _assert_hash_supertrait<T: $tr>() {
fn requires_hash<T: Hash>() {}
let _ = requires_hash::<T>;
}
This only compiles if the bound T: $tr implies T: Hash. And the only way that's the case if Hash is a super-trait of $tr. Also see this helpful Q&A.
Full example (Playground):
trait BadBoi {}
trait GoodBoi: Hash {}
macro_rules! foo {
($tr:ident) => {
fn _assert_hash_supertrait<T: $tr>() {
fn requires_hash<T: Hash>() {}
let _ = requires_hash::<T>;
}
}
}
//foo!(GoodBoi);
foo!(BadBoi);
Of course in this solution, calling foo! twice errors because assert_hash_supertrait is defined twice, but solving that is not part of this question.
I am curious to see how much boilerplate one can save through built-in reflection.
A little background
My idea behind structured logging is to use various small tailored types to separate content from representation. Instead of unstructured logger.info("Found a bar with {} foos", bar.foo) one uses something like logger.info(FoundBar{ _bar: bar })
My Rust-ish approach
define a Log trait
provide a default implementation that calls the Serde machinery to serialize the type (to JSON in this example)
define loggable types easily by letting them "inherit" the default implementation
profit
Define the trait, providing a default impl:
trait Log {
fn to_log(&self) -> String {
serde_json::to_string(&self).unwrap()
}
}
(RLS is already drawing angry red squiggles, but bear with me)
Define a simple type to be logged:
#[derive(Serialize)]
struct Message {
msg: String,
}
and let it use the default implementation:
impl Log for Message {}
and finally the polymorphic logging function defined in terms of the trait:
fn log(log: &Log) {
println!("serialized = {}", log.to_log());
}
The compiler complains:
error[E0277]: the trait bound `Self: _IMPL_DESERIALIZE_FOR_Message::_serde::Serialize` is not satisfied
--> src\main.rs:8:9
|
8 | serde_json::to_string(&self).unwrap()
| ^^^^^^^^^^^^^^^^^^^^^ the trait `_IMPL_DESERIALIZE_FOR_Message::_serde::Serialize` is not implemented for `Self`
|
= help: consider adding a `where Self: _IMPL_DESERIALIZE_FOR_Message::_serde::Serialize` bound
= note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Message::_serde::Serialize` for `&Self`
= note: required by `serde_json::ser::to_string`
Adding the where Self suggestion to my trait function only produces different errors (error[E0433]: failed to resolve. Use of undeclared type or module _IMPL_DESERIALIZE_FOR_Message), but apart from that it seems like a Bad Idea(TM) to have this implementation detail of Serde leak into my code.
How do I portably constrain my trait (using where?) to only apply to types that have the correct derive? Even better, can I "inject" the derive functionality into types using the trait?
If you create a MCVE of your problem on the playground, you get a more accurate error:
error[E0277]: the trait bound `Self: serde::Serialize` is not satisfied
--> src/lib.rs:6:9
|
6 | serde_json::to_string(&self).unwrap()
| ^^^^^^^^^^^^^^^^^^^^^ the trait `serde::Serialize` is not implemented for `Self`
|
= help: consider adding a `where Self: serde::Serialize` bound
= note: required because of the requirements on the impl of `serde::Serialize` for `&Self`
= note: required by `serde_json::ser::to_string`
Following the suggestion, but using the idiomatic supertrait syntax, answers your question:
trait Log: serde::Serialize {
fn to_log(&self) -> String {
serde_json::to_string(&self).unwrap()
}
}
You'll need to change your log function for object-safety reasons:
fn log(log: &impl Log) {
println!("serialized = {}", log.to_log());
}
See also:
The trait cannot be made into an object
Unable to create a polymorphic type because the trait cannot be made into an object
How to implement `serde::Serialize` for a boxed trait object?
How can deserialization of polymorphic trait objects be added in Rust if at all?
Using trait inheritance works, but using the right Serde trait, not the compiler-suggested one:
trait Log: serde::Serialize {
fn to_log(&self) -> String {
serde_json::to_string(&self).unwrap()
}
}
I've run into a problem with piston2d-graphics crate. When I try to use expect() method on Result that I get from graphics::character::CharacterCache::character method, it turns out I can't — because it requires the Error type of the Result to implement std::fmt::Debug trait:
error[E0599]: no method named `expect` found for type `std::result::Result<graphics::character::Character<'_, <G as graphics::Graphics>::Texture>, <C as graphics::character::CharacterCache>::Error>` in the current scope
--> src/some_file.rs:44:53
|
44 | let ch_glyph = glyphs.character(34, ch).expect("Couldn't load character");
| ^^^^^^
|
= note: the method `expect` exists but the following trait bounds were not satisfied:
`<C as graphics::character::CharacterCache>::Error : std::fmt::Debug`
Error here is an associated (nested) type in CharacterCache trait. I can easily submit a PR that adds the requirement and then add it's implementation with a simple derive macro to all other crates. It seems reasonable, because expect() and other related methods are used in Rust all the time, but I'm not sure. Is it the Rust way, or are there reasons not to do it?
I describe the question using example of it's occurrence, but it has nothing specific to do with Piston, my question is about general pattern in Rust. So tag rust-piston is unrelated, please don't add it to the question.
Is it good practice to require associated Error types implement Debug trait?
Yes, when possible. Maybe they forget it.
A way to solve this problem is to use map_err(), here a MCVE of the problem:
struct Error;
fn foo() -> Result<(), Error> {
Ok(())
}
fn main() {
foo().expect("no error");
}
error[E0599]: no method named `expect` found for type `std::result::Result<(), Error>` in the current scope
--> src/main.rs:8:11
|
8 | foo().expect("no error");
| ^^^^^^
|
= note: the method `expect` exists but the following trait bounds were not satisfied:
`Error : std::fmt::Debug`
Use map_err() to produce an error that implement Debug, that could be your own custom Error, In the following exemple, I just return () as Error:
struct Error;
fn foo() -> Result<(), Error> {
Ok(())
}
fn main() {
foo().map_err(|_| ()).expect("no error");
}