This question already has answers here:
Is there a short way to implement Default for a struct that has a field that does not implement Default?
(3 answers)
Closed 1 year ago.
I have a Rust struct with a large number of fields, all of which are themselves Default. I'd like to create a custom impl Default for it, with the following semantics:
One of the fields has a custom value
All other fields get their value from their Default::default
Here's how I hoped to do that:
impl Default for Foo {
fn default() -> Self {
Self {
thing: 2,
..Default::default()
}
}
}
...but that actually causes unchecked recursion, since ..Default::default() calls Self::default() rather than $member::default() for each member of Self.
Is there any way to accomplish this, short of writing a custom macro or explicitly listing every field?
You can use the derivative crate to achieve this. It provides alternative versions of some of the standard library derive macros with additional customizability:
#[derive(Debug, Derivative)]
#[derivative(Default)]
struct Foo {
foo: u8,
#[derivative(Default(value="2"))]
thing: u8,
}
Just using the standard library, you can either derive Default to get the default values for all fields, or implement it completely manually.
Related
This question already has answers here:
Return local String as a slice (&str)
(7 answers)
Proper way to return a new string in Rust
(2 answers)
Is there any way to return a reference to a variable created in a function?
(5 answers)
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed 2 years ago.
I'm working with an external type (i.e., not my code), that has a bunch of &str members:
#[derive(Default, Clone)]
pub struct SomeExternalThingie<'a> {
pub name: &'a str,
pub description: Option<&'a str>,
pub author: Option<&'a str>,
}
I want to make my own function which constructs and returns one of these things. I want to dynamically construct some of the strings used as members:
fn my_func_to_make_a_thingie<'a>(name: &'a str) -> MyThingie<'a> {
let mydesc = format!("Hi, I'm your friendly neighborhood {}!",
name);
SomeExternalThingie {
name: name,
description: Some(mydesc.as_str()),
..Default::default()
}
}
Of course, this won't compile, because the lifetime of mydesc ends when the function does. What's the best practice for dealing with a situation like this? I'm obviously new to Rust, but it seems like this will be a common scenario.
My only thought to change the return type to return both the desired structure and the storage for the string(s)... either by returning a tuple, or making a custom struct. This feels awkward, though, and I was wondering if there was a better way, or at least a convention of sorts.
For some context - the actual use case that prompted this was that I wanted to return a clap::App object. I wanted to do this mostly for organizational reasons - I know that in this case I can just include it in my main function, without the sub-function (even though it makes it longer than I'd like), and I'll probably end up doing this. However, this seems like a common pattern, and I wanted to learn the "Rust way" to deal with this.
This question already has answers here:
Is it possible to access struct fields from within a trait?
(3 answers)
Implementing a trait for multiple types at once
(4 answers)
Closed 3 years ago.
I see some related questions (like this and this) but I'm hoping that my use case for default methods is unique enough to ask a slightly different question. The following minimal example works and outputs "Sheriff Ted" shot "Billy the Kid"!:
#[derive(Debug)]
struct Actor {
name: String,
}
fn main() {
let cop = Actor {
name: String::from("Sheriff Ted"),
};
let robber = Actor {
name: String::from("Billy the Kid")
};
println!("{:?} shot {:?}!", cop.name, robber.name); // without the trait. with:
// cop.shoot(&robber);
}
//pub trait Shoot {
// fn shoot(&self, other: &Actor) {
// println!("\n{:?} shot {:?}!",
// &self.name,
// &other.name,
// )
// }
//}
//
//impl Shoot for Actor {}
As you can see, I want impart the Shoot implementation and the shoot method it contains on the Actor struct. When I uncomment the Shoot trait, its implementation on Actor, and the call cop.shoot(&robber), I get the error message related questions have gotten, as well: error[E0609]: no field 'name' on type '&Self'.
My first thought was to specify &self: Actor in the default method's signature, but that yields the delimiter error, so isn't syntactically valid.
I think this question is unique because the other questions seem to misunderstand how the generics they specify are shadowing their intended types, and in my case I'm not understanding why I can't access fields within the structs on which I am trying to implement a default method.
This works for cases when only Actors need to shoot, but I am looking for a way to apply this behavior (right now, just printlning) across multiple types.
impl Actor {
fn shoot(&self, other: &Actor) {
println!("\n{:?} shot {:?}!",
self.name,
other.name,
)
}
}
You are not trying to implement a default method on any structs; you are implementing it for the trait. Therefore you can't access any fields on any structs; you can only access what the trait demands.
A default implementation of a trait methods means that any type that implements the non-defaulted methods of the trait can use the default method, no matter what it looks like otherwise. But you expect that the implementing type has a name field in addition to what the trait demands (it demands nothing, by the way).
This is simply not a valid assumption.
I wonder why you're using a trait here at all. If you are okay with requiring self to be Actor in the shoot method, why is it a method of a trait? Why isn't it an inherent method of the Actor struct without any traits?
After having read Sebastian's response, I think the "answer" is: you can't name struct fields in traits' default methods because you don't know what fields a struct may have until the implementation of the trait. So you'd define an (abstract?) method signature, and then make it concrete when it's implemented. In my case, this works:
trait Shoot {
fn shoot(&self, other: &Actor);
}
impl Shoot for Actor {
fn shoot(&self, other: &Actor) {
println!("\n{:?} shot {:?}!",
self.name,
other.name,
);
}
}
Still interested to know if I can constrain a trait to be applied only to structs with certain fields and if this is different than "trait bounds". (It is, I think...)
This question already has answers here:
Is there a way other than traits to add methods to a type I don't own?
(2 answers)
How can I add new methods to Iterator?
(1 answer)
Closed 4 years ago.
I have a struct that is used by different functions. Instead of passing the struct as input to the different functions, I think I can implement the struct with all the functions that need to access it. However, there are certain fixed basic functions that I want to provide so that whenever the struct is created, I don't have to implement the same set of functions over and over again.
Put in another way, what I really want is the struct inheritance: I have certain set of methods associated with struct and user can add their custom functions to struct and allow them to access the data contained in data. Is there anyway able to do so?
Concretely, suppose I have a struct called AppContext and the fixed set of functions are new and bdev_name:
pub struct AppContext {
bdev: *mut raw::spdk_bdev,
bdev_desc: *mut raw::spdk_bdev_desc,
bdev_io_channel: *mut raw::spdk_io_channel,
buff: *mut c_char,
bdev_name: *const c_char,
}
impl AppContext {
pub fn new() -> Self {
let context: AppContext;
unsafe {
context = mem::uninitialized();
}
context
}
pub fn bdev_name(&mut self, name: &str) {
self.bdev_name = CString::new(name)
.expect("Couldn't create a string")
.into_raw()
}
}
Now, when I use this struct, I do:
let mut context = AppContext::new();
context.bdev_name("Nvme0n1");
I want to add one extra function (say end()) that can work on the data within the context struct. However, end() is very domain specific function and needed in a specific module, and thus it's not a good idea to implement as part of the context struct.
Is there any way I can workaround the issue (i.e. add custom function to predefined struct)?
I'm working on the rust-efl project, which is a binding to the Enlightenment EFL C library.
There is a function that takes two C-style enums to configure the library. I want to restrict the second argument to a certain enum based on the value of the first argument.
I'll use the actual code for this example since it makes it a bit easier to understand the use case.
Example call:
elementary::policy_set(ElmPolicy::Quit, ElmPolicyQuit::LastWindowClosed as i32);
Library Rust code:
#[repr(C)]
pub enum ElmPolicy {
/// under which circumstances the application should quit automatically. See ElmPolicyQuit
Quit = 0,
/// defines elm_exit() behaviour. See ElmPolicyExit
Exit,
/// defines how throttling should work. See ElmPolicyThrottle
Throttle
}
#[repr(C)]
pub enum ElmPolicyQuit {
/// never quit the application automatically
None = 0,
/// quit when the application's last window is closed
LastWindowClosed,
/// quit when the application's last window is hidden
LastWindowHidden
}
pub fn policy_set(policy: ElmPolicy, value: i32) {
There is an enum similar to ElmPolicyQuit for each value of ElmPolicy. The second argument to policy_set should be of the corresponding enum type.
I would like to modify policy_set so that the caller does not have to cast the value to an i32 by defining a type for value. Ideally, I would like Rust to check that the second argument is of the correct type for the given policy argument.
Implementation Attempt
I'm new to Rust, so this may be way off, but this is my current attempt:
pub fn policy_set<P: ElmPolicy, V: ElmPolicyValue<P>>(policy: P, value: V) {
unsafe { elm_policy_set(policy as c_int, value as c_int) }
}
trait ElmPolicyValue<P> {}
impl ElmPolicyValue<ElmPolicy::Quit> for ElmPolicyQuit {}
But I get this error:
src/elementary.rs:246:22: 246:31 error: ElmPolicy is not a trait
[E0404] src/elementary.rs:246 pub fn policy_set>(policy: P, value: V) {
(arrow points to first argument's type)
I made a dummy trait for ElmPolicy, but then I get
src/elementary.rs:111:21: 111:36 error: found value
elementary::ElmPolicy::Quit used as a type [E0248]
src/elementary.rs:111 impl ElmPolicyValue for
ElmPolicyQuit {}
So it seems like I can't use enums for generic types in this way.
What is the correct way to implement this?
I suppose I don't need these to actually be enums. I just need the values to be convertible to a c_int that corresponds with the EFL library's C enum.
Also, I thought about a single argument instead.
elementary::policy_set(elementary::Policy::Quit::LastWindowClosed);
But nested C-like enums don't seem to work despite documentation I found and I'm uncertain about using #[repr(C)] with nested enums.
Here's how I would do it: instead of defining ElmPolicy as an enum, I'd define it as a trait with an associated type that specifies the parameter type for the policy's value. Each policy would define a unit struct that implements ElmPolicy.
pub trait ElmPolicy {
type Value;
}
pub struct ElmPolicyQuit;
impl ElmPolicy for ElmPolicyQuit {
type Value = ElmPolicyQuitValue;
}
// TODO: ElmPolicyExit and ElmPolicyThrottle
#[repr(C)]
pub enum ElmPolicyQuitValue {
/// never quit the application automatically
None = 0,
/// quit when the application's last window is closed
LastWindowClosed,
/// quit when the application's last window is hidden
LastWindowHidden
}
pub fn policy_set<P: ElmPolicy>(policy: P, value: P::Value) {
// TODO
}
fn main() {
policy_set(ElmPolicyQuit, ElmPolicyQuitValue::LastWindowClosed);
//policy_set(ElmPolicyQuit, ElmPolicyQuitValue::LastWindowClosed as i32); // does not compile
}
You can add methods or supertraits to ElmPolicy and contraints to ElmPolicy::Value as necessary. For example, you might want to add Into<i32> as a constraint on ElmPolicy::Value, so that you can use value.into() in policy_set to convert the value to an i32.
I wouldn't try to solve both problems in one swoop. Create a straight-forward Rust binding to the C library that exposes the API as is (a *-sys package). Then provide a more idiomatic Rust API on top:
enum ElmPolicy {
Quit(QuitDetail),
Exit(ExitDetail),
Throttle(ThrottleDetail),
}
enum QuitDetail {
None,
LastWindowClosed,
LastWindowHidden,
}
Then you can create methods on ElmPolicy that produce a tuple of the C enums, or directly calls the appropriate C function, as desired.
Note that there is likely to be a bit of boilerplate as your enums in the *-sys crate will mirror those in the idiomatic API and you will want to convert between them. Macros may help reduce that.
Consider the following implementation:
pub struct BST {
root: Link,
}
type Link = Option<Box<Node>>;
struct Node {
left: Link,
elem: i32,
right: Link,
}
impl Link { /* misc */ }
impl BST { /* misc */ }
I keep getting the error:
cannot define inherent impl for a type outside of the crate where the type is defined; define and implement a trait or new type instead
I was able to find others had this same issue back in February, but there was seemingly no solution at the time.
Is there any fix or another way for me to implement my Link typedef in Rust?
Is there any fix
Not really. A type alias (type Foo = Bar) does not create a new type. All it does is create a different name that refers to the existing type.
In Rust, you are not allowed to implement inherent methods for a type that comes from another crate.
another way for me to implement
The normal solution is to create a brand new type. In fact, it goes by the name newtype!
struct Link(Option<Box<Node>>);
impl Link {
// methods all up in here
}
There's no runtime disadvantage to this - both versions will take the exact same amount of space. Additionally, you won't accidentally expose any methods you didn't mean to. For example, do you really want clients of your code to be able to call Option::take?
Another solution is to create your own trait, and then implement it for your type. From the callers point of view, it looks basically the same:
type Link = Option<Box<Node>>;
trait LinkMethods {
fn cool_method(&self);
}
impl LinkMethods for Link {
fn cool_method(&self) {
// ...
}
}
The annoyance here is that the trait LinkMethods has to be in scope to call these methods. You also cannot implement a trait you don't own for a type you don't own.
See also:
How do I implement a trait I don't own for a type I don't own?