Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to declare a tuple struct whose members are private, except for initialization?

Is it possible to declare a tuple struct where the members are hidden for all intents and purposes, except for declaring?

// usize isn't public since I don't want users to manipulate it directly
struct MyStruct(usize); 

// But now I can't initialize the struct using an argument to it.
let my_var = MyStruct(0xff)
//                    ^^^^
//                    How to make this work?

Is there a way to keep the member private but still allow new structs to be initialized with an argument as shown above?

As an alternative, a method such as MyStruct::new can be implemented, but I'm still interested to know if its possible to avoid having to use a method on the type since it's shorter, and nice for types that wrap a single variable.


Background

Without going into too many details, the only purpose of this type is to wrap a single type (a helper which hides some details, adds some functionality and is optimized away completely when compiled), in this context it's not exactly exposing hidden internals to use the Struct(value) style initializing. Further, since the wrapper is zero overhead, its a little misleading to use the new method which is often associated with allocation/creation instead of casting.

Just as it's convenient type (int)v or int(v), instead of int::new(v), I'd like to do this for my own type.

It's used often, so the ability to use short expression is very convenient. Currently I'm using a macro which calls a new method, its OK but a little awkward/indirect, hence this question.

like image 551
ideasman42 Avatar asked Nov 14 '16 00:11

ideasman42


People also ask

How to declare struct in Rust?

To define a struct, we enter the keyword struct and name the entire struct. A struct's name should describe the significance of the pieces of data being grouped together. Then, inside curly brackets, we define the names and types of the pieces of data, which we call fields.

What are Structs in Rust?

Similarly, a structure is another user defined data type available in Rust that allows us to combine data items of different types, including another structure. A structure defines data as a key-value pair.

How do I give a struct a default value in Rust?

Implement Default Trait in Rust When #[derive(Default)] is used in a data structure, the compiler constructs a default data structure with the default value in every field. The default Boolean value is false , while the default integral value is 0 as of Boolean. We have used a default value for gpa .


2 Answers

Strictly speaking this isn't possible in Rust.

However the desired outcome can be achieved using a normal struct with a like-named function (yes, this works!)

pub struct MyStruct {
    value: usize,
}

#[allow(non_snake_case)]
pub fn MyStruct(value: usize) -> MyStruct {
    MyStruct { value }
}

Now, you can write MyStruct(5) but not access the internals of MyStruct.

like image 104
SpaceManiac Avatar answered Sep 21 '22 01:09

SpaceManiac


I'm afraid that such a concept is not possible, but for a good reason. Each member of a struct, unless marked with pub, is admitted as an implementation detail that should not raise to the surface of the public API, regardless of when and how the object is currently being used. Under this point of view, the question's goal reaches a conundrum: wishing to keep members private while letting the API user define them arbitrarily is not only uncommon but also not very sensible.

As you mentioned, having a method named new is the recommended approach of doing that. It's not like you're compromising code readability with the extra characters you have to type. Alternatively, for the case where the struct is known to wrap around an item, making the member public can be a possible solution. That, on the other hand, would allow any kind of mutations through a mutable borrow (thus possibly breaking the struct's invariants, as mentioned by @MatthieuM). This decision depends on the intended API.

like image 37
E_net4 stands with Ukraine Avatar answered Sep 19 '22 01:09

E_net4 stands with Ukraine