How to add new argument in rust struct via the method? - rust

in the following example I need to conditionally create other argument called number_3 without adding it to the struct. I wan to add this just like using setattr(self,'number_3',number) in python?
The reason I need this because I don't want the create new object of my class like MyClass { number: i32, number_2: i32, number_3:Some(None)} this number_3:Some(None) is Unnecessary to add. Also, most times I will never need it it is just for some edge cases.
Also, is it possible to initialize it with value None.
pub struct MyClass {
number: i32,
number_2: i32,
}
impl MyClass {
pub fn my_function(mut self) -> i32 {
self.number_3 = my_special_function().unwrap();
if self.number_3 != Some(Nome) {
return self.number * self.number_2 / self.number_3;
} else {
return self.number * self.number_2;
};
};

You cannot.
Besides explicitly initializing the field with None, you have few options:
Providing a constructor that does that (or two, for both cases):
impl MyClass {
pub fn new(number: i32, number_2: i32) -> Self {
Self { number, number_2, number_3: None }
}
pub fn with_three_numbers(number: i32, number_2: i32, number_3: i32) -> Self {
Self { number, number_2, number_3: Some(number_3) }
}
Implementing Default (usually by deriving it) then using the struct update syntax to add the default. This may mean even more boilerplate in your case, but may be worthwhile in case you have many optional fields:
#[derive(Default)]
pub struct MyClass { ... }
MyClass { number: 0, number_2: 1, ..MyClass::default() };
There were, and are, few RFCs and discussions around this subject, so you may be able to have defaulted fields in the future:
Issue #1594, Default values for struct fields (closed).
RFC #1806, Default Struct Field Values (postponed).
Draft RFC, Default field values.
Pre-RFC, User-provided default field values.

Related

How to create a derived column for my struct?

#[derive(Serialize, Deserialize, Debug)]
struct Product {
id: usize,
name: String,
timestamp: i128
}
I deserialize this struct value from a JSON value.
Now I want to expose another property on my struct:
dt: OffsetDateTime
I want this property to be immutable, and set only once. So I don't want to expose a function that like below b/c it would re-calculate each time I call it:
impl Product {
fn dt(&self) -> OffsetDateTime {
OffsetDateTime::from_unix_timestamp_nanos(self.timestamp)
}
}
In java world or other languages I would do something like this:
private dt: OffsetDateTime = null;
public OffsetDateTime getDt() {
if(dt == null) {
dt = OffsetDateTime::from_unix_timestamp_nanos(self.timestamp)
}
return dt;
}
Does Rust have a similar pattern I can use?
You have three options:
Initialize it when initializing the struct, by providing a constructor. This is by far the easiest solution, if initialization isn't expensive or access is common enough that initializing always is not a problem. This is not equivalent to your Java code, however.
Store an Option<OffsetDateTime> and use Option::get_or_insert_with() to initialize it on access. This is cheapier than the third option, but requires a &mut access:
pub fn dt(&mut self) -> &OffsetDateTime {
self.dt.get_or_insert_with(|| { /* Initialization logic */ })
}
Use a library such as once_cell (or the unstable versions in std) to initialize under & access. You can use either Sync or not, depending on whether you need multiple threads to access the data):
pub fn dt(&self) -> &OffsetDateTime {
self.dt.get_or_init(|| { /* Initialization logic */ })
}
You could use an Option to simulate the Java behavior.
struct P {
pub thing: Option<i32>
}
impl P {
pub fn calc_thing( mut self ) -> i32 {
if let None = self.thing {
self.thing = Some(5);
}
self.thing.unwrap()
}
}
fn main(){
let p = P{ thing: None };
println!( "{}", p.calc_thing() );
}

Factory pattern in Rust

I have a Terminal and a TerminalFactory type. What I want to achieve is a factory pattern or at least an implementation that is similar to it in regards to some key aspects.
In particular, I want every Terminal to have specific properties (e.G. id) that are set by TerminalFactory. In GRASP terms, TerminalFactory is the Creator and the Information Expert because it knows next_id.
TerminalFactory is not a singleton, it is an instance that will be injected in a container that will be handed around where necessary (I'm trying to implement an application based on the composite pattern to achieve the OCP of SOLID).
It looks like everything is in line with the fact that Rust discourages static state unless it's unsafe code.
The problem now is that instances of Terminal have an id which should not be set by arbitrary code. Therefore, it's not pub. On the other hand, it can be gotten. So I added a public getter, like this:
pub struct Terminal {
id: u32, // private
pub name: String
}
impl Terminal {
pub fn get_id(self: &Self) -> u32 {
self.id
}
}
As far as I can tell, there is no friend keyword in rust, no static state I can keep in the Terminal type and TerminalFactory cannot set Terminal::id during creation because it's not public.
I have the impression I can't implement the factory pattern correctly. Maybe I shouldn't even try to transfer "classical patterns" to Rust? Then what about the SOLID principles which are absolutely necessary to manage change in medium-scale applications (say, 50+ types and beyond 10000 lines of code)?
By adding an associate function new(id : u32) to Terminal I completely defeat the purpose of the factory. So this won't make sense, either.
As all of this code will be in a library that is consumed by other Rust code, how can I protect the consumer code from creating broken instances?
Put both types in the same module:
mod terminal {
pub struct Terminal {
id: u32,
pub name: String
}
impl Terminal {
pub fn get_id(&self) -> u32 {
self.id
}
}
pub struct TerminalFactory {
next_id: u32,
}
impl TerminalFactory {
pub fn new() -> Self {
Self {
next_id: 0,
}
}
pub fn new_terminal(&mut self, name: &str) -> Terminal {
let next_id = self.next_id;
self.next_id += 1;
Terminal {
id: next_id,
name: name.to_owned(),
}
}
}
}
Then this is OK:
let mut tf = terminal::TerminalFactory::new();
let t0 = tf.new_terminal("foo");
let t1 = tf.new_terminal("bar");
println!("{} {}", t0.get_id(), t0.name);
println!("{} {}", t1.get_id(), t1.name);
But this is not:
println!("{} {}", t0.id, t0.name); // error: private field
See Visibility and privacy for other scenarios.

Idiomatic means of Parsing GUI Input Strings for Modular UI Components in Rust

I'm creating some User Input components in Rust. I'm trying to modularize these components using trait CustomInput. This trait implements some basic for all UI Input components, like being able to set and get the values of the component. All my UI components will take a String input, and parse that string to some typed value, maybe an f64, i32, or Path. Because different UI components can return different types, I created enum CustomOutputType, so that get_value can have a single return type for all components.
As users can input any random string, each UI component needs to have a means of ensuring that the input string can be successfully converted to the right type for the respective input component, I.e MyFloatInput needs to return a f64 value, MyIntInput needs to return an i32, and so on. I see that std::str::FromStr is implemented for most basic types, bool, f64, usize, but I don't think this kind of parsing is robust enough for UI inputs.
I'd like some more advanced functionality than std::str::FromStr provides, I'd like to be able to:
Evaluate expression, i.e input of 500/25 returns 20
Floor/Ceiling for min/max values: i.e if max is 1000 and input is 2000, value is 1000
What would be an idiomatic way of implementing such parsing
functionality for my UI components?
Is using the CustomOutputType enum an efficient strategy for handling the
different types the UI Components could return?
Would a parsing crate like Nom be advisable in this situation? I think this might be
overkill for what I'm doing, but I'm not sure.
I've taken a stab at creating such a system:
use std::str::FromStr;
use snafu::{Snafu};
#[derive(Debug, Snafu)]
pub enum Error{
#[snafu(display("Incorrect Type: {:?}", msg))]
IncorrectInputType{msg: String},
}
type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Clone, Debug)]
pub enum CustomOutputType{
CFloat(f64),
CInt(i32),
}
pub trait CustomInput{
fn get_value(&self)->CustomOutputType;
fn set_value(&mut self, val: String)->Result<()>;
}
pub struct MyFloatInput{
val: f64,
}
pub struct MyIntInput{
val: i32
}
impl CustomInput for MyFloatInput{
fn get_value(&self)->CustomOutputType{
CustomOutputType::CFloat(self.val)
}
fn set_value(&mut self, val: String)->Result<()>{
match f64::from_str(&val) {
Ok(inp)=>Ok(self.val = inp),
// Ok(inp)=>{self.val = inp}
Err(e) => IncorrectInputType { msg: "setting float input failed".to_string() }.fail()?
}
}
}
impl CustomInput for MyIntInput{
fn get_value(&self)->CustomOutputType{
CustomOutputType::CInt(self.val)
}
fn set_value(&mut self, val: String)->Result<()>{
match i32::from_str(&val) {
Ok(inp)=>Ok(self.val = inp),
Err(e) => IncorrectInputType { msg: "setting int input failed".to_string() }.fail()?
}
}
}
fn main() {
let possible_inputs = vec!["100".to_string(), "100.0".to_string(), "100/2".to_string(), ".1".to_string(), "teststr".to_string()];
let mut int_input = MyIntInput{val: 0};
let mut float_input = MyFloatInput{val: 0.0};
for x in &possible_inputs{
int_input.set_value(x.to_string()).unwrap();
float_input.set_value(x.to_string()).unwrap();
}
}

What is an idiomatic way to have multiple structs with the same properties in Rust?

I'm aware that Rust does not have inheritance and that the language provides and easy way to share different implementations of the same methods across objects through the use of Traits. But is there an idiomatic way to share property name definitions or do they need to be defined on each struct?
My use case is that I have many different structs that track some information. Each piece of information can be updated and I want each struct to know the date of its last update. Is there a common pattern (maybe macros?) to add a last_update property to all the structs or must I add it to each struct explicitly?
There is currently no way to do this via traits, the closest thing is the "Fields in Traits" RFC (discussion, RFC), but that doesn't seem terribly active as of now.
The simplest way to do this is to have a type / struct with a method and include that field in any struct you want:
struct UpdateTimestamp {
timestamp: Timestamp, // dummy type
}
impl UpdateTimestamp {
fn update(&mut self) {
self.timestamp = now(); // dummy function
}
fn last_updated(&self) -> Timestamp {
self.timestamp
}
}
You could then include this in any struct where you want the functionality:
struct MyStruct {
my_field: u32,
my_other_field: i32,
update_ts: UpdateTimestamp,
}
impl MyStruct {
fn my_field(&self) -> u32 {
// Getter - no update
self.my_field
}
fn set_my_field(&mut self, my_field: u32) {
self.update_ts.update();
self.my_field = my_field;
}
fn last_updated(&self) -> Timestamp {
self.update_ts.last_updated()
}
}
Now you could write a complicated macro for this which automates the implementation part (injects updates into the setters and the last_updated method in the impl block), but unless you're doing this a lot I don't think it would be worth it.

Why must callers use a constructor instead of creating a struct directly?

Consider the following Rust snippet from The Rust Programming Language, second edition:
pub struct Guess {
value: u32,
}
impl Guess {
pub fn new(value: u32) -> Guess {
if value < 1 || value > 100 {
panic!("Guess value must be between 1 and 100, got {}.", value);
}
Guess {
value
}
}
pub fn value(&self) -> u32 {
self.value
}
}
and commentary from the corresponding tutorial, emphasis mine:
Next, we implement a method named value that borrows self, doesn’t have any
other parameters, and returns a u32. This is a kind of method sometimes
called a getter, since its purpose is to get some data from its fields and
return it. This public method is necessary because the value field of the
Guess struct is private. It’s important that the value field is private so
that code using the Guess struct is not allowed to set value directly:
callers outside the module must use the Guess::new function to create an
instance of Guess, which ensures there’s no way for a Guess to have a
value that hasn’t been checked by the conditions in the Guess::new function.
Why must callers use the new function? Couldn't they get around the requirement that Guess.value be between 1 and 100 by doing something like:
let g = Guess { value: 200 };
This applies only when the Guess struct is defined in a different module than the code using it; the struct itself is public but its value field is not, so you can't access it directly.
You can verify it with the following example (playground link):
use self::guess::Guess;
fn main() {
let guess1 = Guess::new(20); // works
let guess2 = Guess::new(200); // panic: 'Guess value must be between 1 and 100, got 200.'
let guess3 = Guess { value: 20 }; // error: field `value` of struct `guess::Guess` is private
let guess4 = Guess { value: 200 }; // error: field `value` of struct `guess::Guess` is private
}
mod guess {
pub struct Guess {
value: u32,
}
impl Guess {
pub fn new(value: u32) -> Guess {
if value < 1 || value > 100 {
panic!("Guess value must be between 1 and 100, got {}.", value);
}
Guess {
value
}
}
pub fn value(&self) -> u32 {
self.value
}
}
}
The Book explains the rationale behind keeping a struct's contents private pretty well.

Resources