rust


Similar implementations of one trait for many structs


In the below code the only different in implementation is in the println!.
It feels like there should be a way for me not to have to write out two completely different implementations, however I have not found a way.
pub trait ChangeDecision{
fn change_decision(&mut self);
}
impl ChangeDecision for Hero{
fn change_decision(&mut self){
self.should_change_decision = false;
let rand_num = rand::thread_rng().gen_range(1, 101) as f32 / 100.;
let mut prob_counter = 0.0;
for (action, prob) in &mut self.decisions.iter(){
prob_counter += *prob;
match prob_counter{
p if rand_num > p => {},
_ => {println!("{}: {:?}", self.name, action); self.current_decision = *action; break},
}
}
}
}
impl ChangeDecision for Team{
fn change_decision(&mut self){
self.should_change_decision = false;
let rand_num = rand::thread_rng().gen_range(1, 101) as f32 / 100.;
let mut prob_counter = 0.0;
for (action, prob) in &mut self.decisions.iter(){
prob_counter += *prob;
match prob_counter{
p if rand_num > p => {},
_ => {println!("{:?}: {:?}", self.side, action); self.current_decision = *action; break},
}
}
}
}
When the implementations are exactly identical I can use a macro to implement for both. i.e.
macro_rules! impl_SimilarStuff {
($T:ident) => {
impl SimilarStuff for $T{
fn my_func(&mut self){
true
}
}
}
}
impl_SimilarStuff!(ThingOne);
impl_SimilarStuff!(ThingTwo);
However I could not find any examples of 'macro conditionality'
The way I would handle this is to use another trait to handle the differing parts. Something like:
trait PrintSomething {
fn print_something(&self, action: Action);
}
impl PrintSomething for Hero {
fn print_something(&self, action: Action) {
println!("{}: {:?}", self.name, action);
}
}
impl PrintSomething for Team {
fn print_something(&self, action: Action) {
println!("{}: {:?}", self.side, action);
}
}
// Now the macro would expand to:
impl ChangeDecision for Hero {
fn change_decision(&mut self){
self.should_change_decision = false;
let rand_num = rand::thread_rng().gen_range(1, 101) as f32 / 100.;
let mut prob_counter = 0.0;
for (action, prob) in &mut self.decisions.iter(){
prob_counter += *prob;
match prob_counter{
p if rand_num > p => {},
_ => {
self.print_something(action);
self.current_decision = *action;
break
},
}
}
}
}
You could pass the "conditional" parts to your macros as separate parameters. Along the lines of:
struct S1 {n1 : isize}
struct S2 {n2 : isize}
trait T {
fn print_me(self);
}
macro_rules! doit {
($t: ty, $member: ident) => (
impl T for $t {
fn print_me(self) {
println!("{}", self.$member);
}
}
)
}
doit!(S1, n1);
doit!(S2, n2);
fn main() {
let s1 = S1 {n1: 1};
let s2 = S2 {n2: 2};
s1.print_me();
s2.print_me();
}
If the "custom part" is bigger than some simple statements, you may consider extracting the custom part into an own trait, as suggested by #Chris Emerson.
Alternatively, you might try to write a generic function taking a something satisfying your trait and the custom part as a closure. This, however, may involve modifying your trait.

Related Links

How to get the name of current program without the directory part?
Changing key of HashMap from child method
Cannot build a delete function for a binary search tree in Rust because the borrowed value does not live long enough
Why does AtomicUsize not implement Send?
How can I define a list of functions to call? [duplicate]
How can I tell if a Rust library is deprecated?
error: non-scalar cast: `core::option::Option<i32>` as `usize`
Lifetime of variable in map/flat_map in Rust
Can associated constants be used to initialize fixed size arrays?
Why do Arc and Mutex allow me to change the value of an immutable variable?
Unable to download a package via cargo — timeout
“borrowed value does not live long enough” seems to blame the wrong thing
Is the destructor of Arc guaranteed to be called before upgrading a Weak reference will return None?
Can't find crate for `rayon`
How to write a function that returns Vec<Path>?
How to implement a long running process with progress in Rust, available via a Rest api?

Categories

HOME
svn
scroll
foaf
ant
website
openlayers-3
google-play-services
tibco
ag-grid
minecraft
anchor
mutation-testing
business-intelligence
responsivevoice
pm2
squid
supervisord
fresco
phonegap-build
l20n
office-ui-fabric
multiple-tables
conda
react-dnd
mod-wsgi
data-collection
ipa
tsung
bitbake
fusion
docx4j
monitor
nic
phpstorm-2016.1
seafile-server
appcode
listjs
cloudera-manager
adminer
grails-2.5
cargo
best-buy-api
contactless-smartcard
dbcc
latexml
transparency
dredd
scala-breeze
solr-query-syntax
extjs4.1
iptv
ptvs
clrs
dex
openerp-6
yui3
rational-performance-test
jpda
groovyfx
okta-api
ioexception
webgrind
textpattern
arbre
hmisc
supercomputers
gql
search-form
kefir.js
tree-structure
directorysearcher
wicket-1.5
visual-studio-6
nidaqmx
xcode6.3.1
coding-efficiency
.htpasswd
django-sites
meteorite
hyphen
postgres-xc
eager-loading
rikulo
spiral
days
red-system
struts2-json-plugin
live-wallpaper
server-name
autosize
exponent
navigationcontroller
infopath-2007
delphi-prism
getopts
kohana-auth
servlet-container
git-log
formal-semantics
active-record-query
raw-data
cleartype
aspbutton
rawcontacts
spring-modules

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App