How to overload the 'new' method? - struct

I'm just started to learn Rust and I'm wondering if there is way to overload methods.
At first I created a struct and used a 'impl' to implement basic 'new' method. Then I thought to add 'new' method with some params, and I tried to use trait for that.
The following code was successfully compiled but once I tried to use 'new' with params, compiler gave me an error about extra params.
So how should I overload methods in Rust?
pub struct Words<'a> {
pub nouns: Vec<&'a str>,
}
trait Test<'a>{
fn new(nouns: Vec<&'a str>) -> Self;
}
impl<'a> Words<'a> {
pub fn new() -> Words<'a>{
let nouns = vec!["test1", "test2", "test3", "test4"];
Words{ nouns: nouns }
}
pub fn print(&self){
for i in self.nouns.iter(){
print!("{} ", i);
}
}
}
impl<'a> Test<'a> for Words<'a> {
fn new(nouns: Vec<&'a str>) -> Words<'a>{
Words{ nouns: nouns }
}
}

Rust indeed has overloading via traits, but you can't change the number of parameters, and their types can only be changed if they were declared as generic on the first place in the trait definition.
In cases like yours, it's common to have a method like new_with_nouns to specialize what you mean:
impl<'a> Words<'a> {
fn new() -> Words { /* ... */ }
fn new_with_nouns(nouns: Vec<&'a str>) -> Words<'a> { /* ... */ }
}
For more complex data structures, where the new_with_something pattern would lead to a combinatorial explosion, the builder pattern is common (here I'll assume that Words has a separator field, just to demonstrate):
struct WordsBuilder<'a> {
separator: Option<&'a str>,
nouns: Option<Vec<&'a str>>,
}
impl<'a> WordsBuilder<'a> {
fn new() -> WordsBuilder<'a> {
WordsBuilder { separator: None, nouns: None }
}
fn nouns(mut self, nouns: Vec<&'a str>) -> WordsBuilder<'a> {
self.nouns = Some(nouns);
self
}
fn separator(mut self, separator: &'a str) -> WordsBuilder<'a> {
self.separator = Some(separator);
self
}
fn build(self) -> Words<'a> {
Words {
separator: self.separator.unwrap_or(","),
nouns: self.nouns.unwrap_or_else(|| {
vec!["test1", "test2", "test3", "test4"]
})
}
}
}
This is similar to how the stdlib's thread::Builder works, for example.

Related

How do I dynamically create a struct from a string from input?

Given a situation where we receive inputs for some nodes type like 'nodeA' or 'nodeB', and we want to initialize structs with that same input. Is it possible without a gigantic switch block? These structs share similar behaviour (using a Trait for that) but with some differences.
pub trait Executable {
fn run(&self);
}
pub struct NodeA {}
impl Executable for NodeA {
fn run(&self) {}
}
pub struct NodeB {}
impl Executable for NodeB {
fn run(&self) {}
}
Flow:
User inputs 'nodeA'
Program initializes struct nodeA with some data
User inputs 'nodeB'
Program initializes struct nodeB with some data
...
To specify better, the final use case is reading a JSON file with all the nodes and respective params to be instantiated. Some of those nodes can come from external plugins, so the number of existing nodes can become very big.
For smaller, static number of nodes, I think a match - case construct is perfectly fine.
But if you have a larger number of nodes, or the available nodes is dynamically changing, I would implement something like this:
pub trait Executable {
fn run(&self);
}
pub struct NodeA {}
impl Executable for NodeA {
fn run(&self) {
println!("NodeA::run()");
}
}
pub struct NodeB {}
impl Executable for NodeB {
fn run(&self) {
println!("NodeB::run()");
}
}
pub trait Matcher {
fn try_match(&self, s: &str) -> Option<Box<dyn Executable>>;
}
pub struct NodeAMatcher;
pub struct NodeBMatcher;
impl Matcher for NodeAMatcher {
fn try_match(&self, s: &str) -> Option<Box<dyn Executable>> {
(s == "NodeA").then(|| Box::new(NodeA {}) as Box<dyn Executable>)
}
}
impl Matcher for NodeBMatcher {
fn try_match(&self, s: &str) -> Option<Box<dyn Executable>> {
(s == "NodeB").then(|| Box::new(NodeB {}) as Box<dyn Executable>)
}
}
struct MatcherRegistry {
matchers: Vec<Box<dyn Matcher>>,
}
impl MatcherRegistry {
fn new() -> Self {
Self { matchers: vec![] }
}
fn register_matcher(&mut self, matcher: impl Matcher + 'static) {
self.matchers.push(Box::new(matcher));
}
fn try_get_node(&self, s: &str) -> Option<Box<dyn Executable>> {
self.matchers
.iter()
.filter_map(|matcher| matcher.try_match(s))
.next()
}
fn try_execute(&self, s: &str) {
if let Some(node) = self.try_get_node(s) {
node.run();
} else {
println!("'{}' not found.", s);
}
}
}
fn main() {
let mut registry = MatcherRegistry::new();
registry.register_matcher(NodeAMatcher);
registry.register_matcher(NodeBMatcher);
registry.try_execute("NodeA");
registry.try_execute("NodeB");
registry.try_execute("NodeC");
}
NodeA::run()
NodeB::run()
'NodeC' not found.
Here, you have a factory pattern.
The structs NodeAMatcher and NodeBMatcher are factories for NodeA and NodeB. They can check if the input matches, and then create an Executable object.
Then, you collect all possible factories (or Matchers here) in a registry, here called MatcherRegistry. You can then, at runtime, add or remove matchers as you wish.
Of course, if you don't need to create a new object every time and the act of executing doesn't consume it, you can reduce the complexity a little by bypassing the factory pattern:
use std::collections::HashMap;
pub trait Executable {
fn run(&self);
}
pub struct NodeA {}
impl Executable for NodeA {
fn run(&self) {
println!("NodeA::run()");
}
}
pub struct NodeB {}
impl Executable for NodeB {
fn run(&self) {
println!("NodeB::run()");
}
}
struct ExecutableRegistry {
executables: HashMap<&'static str, Box<dyn Executable>>,
}
impl ExecutableRegistry {
fn new() -> Self {
Self {
executables: HashMap::new(),
}
}
fn register_executable(
&mut self,
command: &'static str,
executable: impl Executable + 'static,
) {
self.executables.insert(command, Box::new(executable));
}
fn try_execute(&self, s: &str) {
if let Some(node) = self.executables.get(s) {
node.run();
} else {
println!("'{}' not found.", s);
}
}
}
fn main() {
let mut registry = ExecutableRegistry::new();
registry.register_executable("NodeA", NodeA {});
registry.register_executable("NodeB", NodeB {});
registry.try_execute("NodeA");
registry.try_execute("NodeB");
registry.try_execute("NodeC");
}
Of course there exists a large mount of other variations of the same patterns. Which one you implement is up to you and your usecase.

Rust: How to return a reference to an Rc<RefCell<HashMap<K, V>> value?

I'm trying to learn Rust and I'm having some problems with different smart pointers and stuff.
Here is my code:
pub struct MyMap<T> {
map: Rc<RefCell<HashMap<String, T>>>,
}
impl <T> MyMap<T> {
// Not entire sure if it's supposed to be Option<Ref<T>> or something else here.
pub fn get(&self, key: &str) -> Option<Ref<T>> {
todo!("What do I do here?")
}
}
The closest I've got is by searching the HashMap twice:
impl <T> MyMap<T> {
pub fn get(&self, key: &str) -> Option<Ref<T>> {
if self.map.borrow().contains_key(key) {
Some(Ref::map(self.map.borrow(), |m| m.get(key).unwrap()))
} else {
None
}
}
}
Which isn't very elegant to say the least.
Two solutions that come to my mind:
Use the unstable Ref::filter_map, which will potentially be stabilized in 1.63.0.
Use a context manager pattern, which circumvents the entire problem.
filter_map:
#![feature(cell_filter_map)]
use std::{
cell::{Ref, RefCell},
collections::HashMap,
rc::Rc,
};
pub struct MyMap<T> {
map: Rc<RefCell<HashMap<String, T>>>,
}
impl<T> MyMap<T> {
pub fn get(&self, key: &str) -> Option<Ref<T>> {
Ref::filter_map(self.map.borrow(), |map| map.get(key)).ok()
}
}
fn main() {
let map: MyMap<u32> = MyMap {
map: Rc::new(RefCell::new(HashMap::from([
("meaning".to_string(), 42),
("nice".to_string(), 69),
]))),
};
println!("{:?}", map.get("meaning"));
}
Some(42)
Context manager:
The idea here is that instead of returning a reference, you pass in a closure of the action that needs the value. That entirely circumvents the lifetime problem, because the variables inside of the get (or with_value in the example below) are still in scope while the closure gets executed.
use std::{cell::RefCell, collections::HashMap, rc::Rc};
pub struct MyMap<T> {
map: Rc<RefCell<HashMap<String, T>>>,
}
impl<T> MyMap<T> {
pub fn with_value<F, O>(&self, key: &str, f: F) -> O
where
F: FnOnce(Option<&T>) -> O,
{
f(self.map.borrow().get(key))
}
}
fn main() {
let map: MyMap<u32> = MyMap {
map: Rc::new(RefCell::new(HashMap::from([
("meaning".to_string(), 42),
("nice".to_string(), 69),
]))),
};
map.with_value("meaning", |value| {
println!("{:?}", value);
});
}
Some(42)

Allowing extension (beyond the crate) of implementation with event loop

Within the crate we can happily do something like this:
mod boundary {
pub struct EventLoop;
impl EventLoop {
pub fn run(&self) {
for _ in 0..2 {
self.handle("bundled");
self.foo();
}
}
pub fn handle(&self, message: &str) {
println!("{} handling", message)
}
}
pub trait EventLoopExtend {
fn foo(&self);
}
}
use boundary::EventLoopExtend;
impl EventLoopExtend for boundary::EventLoop {
fn foo(&self) {
self.handle("extended")
}
}
fn main() {
let el = boundary::EventLoop{};
el.run();
}
But if mod boundary were a crate boundary we get error[E0117]: only traits defined in the current crate can be implemented for arbitrary types.
I gather that a potential solution to this could be the New Type idiom, so something like this:
mod boundary {
pub struct EventLoop;
impl EventLoop {
pub fn run(&self) {
for _ in 0..2 {
self.handle("bundled");
self.foo();
}
}
pub fn handle(&self, message: &str) {
println!("{} handling", message)
}
}
pub trait EventLoopExtend {
fn foo(&self);
}
impl EventLoopExtend for EventLoop {
fn foo(&self) {
self.handle("unimplemented")
}
}
}
use boundary::{EventLoop, EventLoopExtend};
struct EventLoopNewType(EventLoop);
impl EventLoopExtend for EventLoopNewType {
fn foo(&self) {
self.0.handle("extended")
}
}
fn main() {
let el = EventLoopNewType(EventLoop {});
el.0.run();
}
But then the problem here is that the extended trait behaviour isn't accessible from the underlying EventLoop instance.
I'm still quite new to Rust, so I'm sure I'm missing something obvious, I wouldn't be surprised if I need to take a completely different approach.
Specifically in my case, the event loop is actually from wgpu, and I'm curious if it's possible to build a library where end users can provide their own "render pass" stage.
Thanks to #AlexN's comment I dug deeper into the Strategy Pattern and found a solution:
mod boundary {
pub struct EventLoop<'a, T: EventLoopExtend> {
extension: &'a T
}
impl<'a, T: EventLoopExtend> EventLoop<'a, T> {
pub fn new(extension: &'a T) -> Self {
Self { extension }
}
pub fn run(&self) {
for _ in 0..2 {
self.handle("bundled");
self.extension.foo(self);
}
}
pub fn handle(&self, message: &str) {
println!("{} handling", message)
}
}
pub trait EventLoopExtend {
fn foo<T: EventLoopExtend>(&self, el: &EventLoop<T>) {
el.handle("unimplemented")
}
}
}
use boundary::{EventLoop, EventLoopExtend};
struct EventLoopExtension;
impl EventLoopExtend for EventLoopExtension {
fn foo<T: EventLoopExtend>(&self, el: &EventLoop<T>) {
el.handle("extended")
}
}
fn main() {
let el = EventLoop::new(&EventLoopExtension {});
el.run();
}
The basic idea is to use generics with a trait bound. I think the first time I looked into this approach I was worried about type recursion. But it turns out passing the EventLoop object as an argument to EventLoopExtend trait methods is perfectly reasonable.

Add an element to a mutable vector list in Rust

Here is a link to a playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=1e82dcd3d4b7d8af89c5c00597d2d938
I am a newbie learning rust and trying to simply update a mutable vector on a struct.
struct Friend<'a> {
name: &'a str
}
impl <'a> Friend<'a> {
fn new(name: &'a str) -> Self { Self { name } }
}
struct FriendsList<'a> {
name: &'a str,
friends: Vec<Friend<'a>>
}
impl <'a> FriendsList<'a> {
fn new(name: &'a str, friends: Vec<Friend<'a>>) -> Self { Self { name, friends } }
fn add_new_friend(&self, friend: Friend) {
// how to make this work?
todo!()
// self.friends.push(friend)
}
}
fn main() {
let friends_list = FriendsList::new("George",
vec![
Friend::new("bob"),
Friend::new("bobby"),
Friend::new("bobbo")
]
);
}
specifically how do I make this fn add_new_friend(&self, friend: Friend) method work? That is, push a new element to field friends on the FriendsList struct. Is there a more idiomatic approach? When I try making things mutable, I get a whole bunch of errors I am not sure how to fix...
You have to borrow self mutably:
impl <'a> FriendsList<'a> {
// [...]
fn add_new_friend(&mut self, friend: Friend<'a>) {
self.friends.push(friend)
}
}

Is there an owned version of String::chars?

The following code does not compile:
use std::str::Chars;
struct Chunks {
remaining: Chars,
}
impl Chunks {
fn new(s: String) -> Self {
Chunks {
remaining: s.chars(),
}
}
}
The error is:
error[E0106]: missing lifetime specifier
--> src/main.rs:4:16
|
4 | remaining: Chars,
| ^^^^^ expected lifetime parameter
Chars doesn't own the characters it iterates over and it can't outlive the &str or String it was created from.
Is there an owned version of Chars that does not need a lifetime parameter or do I have to keep a Vec<char> and an index myself?
std::vec::IntoIter is an owned version of every iterator, in a sense.
use std::vec::IntoIter;
struct Chunks {
remaining: IntoIter<char>,
}
impl Chunks {
fn new(s: String) -> Self {
Chunks {
remaining: s.chars().collect::<Vec<_>>().into_iter(),
}
}
}
Playground link
Downside is additional allocation and a space overhead, but I am not aware of the iterator for your specific case.
Ouroboros
You can use the ouroboros crate to create a self-referential struct containing the String and a Chars iterator:
use ouroboros::self_referencing; // 0.4.1
use std::str::Chars;
#[self_referencing]
pub struct IntoChars {
string: String,
#[borrows(string)]
chars: Chars<'this>,
}
// All these implementations are based on what `Chars` implements itself
impl Iterator for IntoChars {
type Item = char;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.with_mut(|me| me.chars.next())
}
#[inline]
fn count(mut self) -> usize {
self.with_mut(|me| me.chars.count())
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.with(|me| me.chars.size_hint())
}
#[inline]
fn last(mut self) -> Option<Self::Item> {
self.with_mut(|me| me.chars.last())
}
}
impl DoubleEndedIterator for IntoChars {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.with_mut(|me| me.chars.next_back())
}
}
impl std::iter::FusedIterator for IntoChars {}
// And an extension trait for convenience
trait IntoCharsExt {
fn into_chars(self) -> IntoChars;
}
impl IntoCharsExt for String {
fn into_chars(self) -> IntoChars {
IntoCharsBuilder {
string: self,
chars_builder: |s| s.chars(),
}
.build()
}
}
See also:
How can I store a Chars iterator in the same struct as the String it is iterating on?
Rental
You can use the rental crate to create a self-referential struct containing the String and a Chars iterator:
#[macro_use]
extern crate rental;
rental! {
mod into_chars {
pub use std::str::Chars;
#[rental]
pub struct IntoChars {
string: String,
chars: Chars<'string>,
}
}
}
use into_chars::IntoChars;
// All these implementations are based on what `Chars` implements itself
impl Iterator for IntoChars {
type Item = char;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.rent_mut(|chars| chars.next())
}
#[inline]
fn count(mut self) -> usize {
self.rent_mut(|chars| chars.count())
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.rent(|chars| chars.size_hint())
}
#[inline]
fn last(mut self) -> Option<Self::Item> {
self.rent_mut(|chars| chars.last())
}
}
impl DoubleEndedIterator for IntoChars {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.rent_mut(|chars| chars.next_back())
}
}
impl std::iter::FusedIterator for IntoChars {}
// And an extension trait for convenience
trait IntoCharsExt {
fn into_chars(self) -> IntoChars;
}
impl IntoCharsExt for String {
fn into_chars(self) -> IntoChars {
IntoChars::new(self, |s| s.chars())
}
}
See also:
How can I store a Chars iterator in the same struct as the String it is iterating on?
There's also the owned-chars crate, which
provides an extension trait for String with two methods, into_chars and into_char_indices. These methods parallel String::chars and String::char_indices, but the iterators they create consume the String instead of borrowing it.
You could implement your own iterator, or wrap Chars like this (with just one small unsafe block):
// deriving Clone would be buggy. With Rc<>/Arc<> instead of Box<> it would work though.
struct OwnedChars {
// struct fields are dropped in order they are declared,
// see https://stackoverflow.com/a/41056727/1478356
// with `Chars` it probably doesn't matter, but for good style `inner`
// should be dropped before `storage`.
// 'static lifetime must not "escape" lifetime of the struct
inner: ::std::str::Chars<'static>,
// we need to box anyway to be sure the inner reference doesn't move when
// moving the storage, so we can erase the type as well.
// struct OwnedChar<S: AsRef<str>> { ..., storage: Box<S> } should work too
storage: Box<AsRef<str>>,
}
impl OwnedChars {
pub fn new<S: AsRef<str>+'static>(s: S) -> Self {
let storage = Box::new(s) as Box<AsRef<str>>;
let raw_ptr : *const str = storage.as_ref().as_ref();
let ptr : &'static str = unsafe { &*raw_ptr };
OwnedChars{
storage: storage,
inner: ptr.chars(),
}
}
pub fn as_str(&self) -> &str {
self.inner.as_str()
}
}
impl Iterator for OwnedChars {
// just `char` of course
type Item = <::std::str::Chars<'static> as Iterator>::Item;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl DoubleEndedIterator for OwnedChars {
fn next_back(&mut self) -> Option<Self::Item> {
self.inner.next_back()
}
}
impl Clone for OwnedChars {
fn clone(&self) -> Self {
// need a new allocation anyway, so simply go for String, and just
// clone the remaining string
OwnedChars::new(String::from(self.inner.as_str()))
}
}
impl ::std::fmt::Debug for OwnedChars {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
let storage : &str = self.storage.as_ref().as_ref();
f.debug_struct("OwnedChars")
.field("storage", &storage)
.field("inner", &self.inner)
.finish()
}
}
// easy access
trait StringExt {
fn owned_chars(self) -> OwnedChars;
}
impl<S: AsRef<str>+'static> StringExt for S {
fn owned_chars(self) -> OwnedChars {
OwnedChars::new(self)
}
}
See playground
As copied from How can I store a Chars iterator in the same struct as the String it is iterating on?:
use std::mem;
use std::str::Chars;
/// I believe this struct to be safe because the String is
/// heap-allocated (stable address) and will never be modified
/// (stable address). `chars` will not outlive the struct, so
/// lying about the lifetime should be fine.
///
/// TODO: What about during destruction?
/// `Chars` shouldn't have a destructor...
struct OwningChars {
_s: String,
chars: Chars<'static>,
}
impl OwningChars {
fn new(s: String) -> Self {
let chars = unsafe { mem::transmute(s.chars()) };
OwningChars { _s: s, chars }
}
}
impl Iterator for OwningChars {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
self.chars.next()
}
}
Here is a solution without unsafe.
It provides the same effect as s.chars().collect::<Vec<_>>().into_iter(), but without the allocation overhead.
struct OwnedChars {
s: String,
index: usize,
}
impl OwnedChars {
pub fn new(s: String) -> Self {
Self { s, index: 0 }
}
}
impl Iterator for OwnedChars {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
// Slice of leftover characters
let slice = &self.s[self.index..];
// Iterator over leftover characters
let mut chars = slice.chars();
// Query the next char
let next_char = chars.next()?;
// Compute the new index by looking at how many bytes are left
// after querying the next char
self.index = self.s.len() - chars.as_str().len();
// Return next char
Some(next_char)
}
}
Together with a little bit of trait magic:
trait StringExt {
fn into_chars(self) -> OwnedChars;
}
impl StringExt for String {
fn into_chars(self) -> OwnedChars {
OwnedChars::new(self)
}
}
You can do:
struct Chunks {
remaining: OwnedChars,
}
impl Chunks {
fn new(s: String) -> Self {
Chunks {
remaining: s.into_chars(),
}
}
}

Resources