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

Nesting an iterator's loops
Do literal integral values have a specific type in Rust?
What value does the variable in the following code snippet have?
How do you import macros in submodules in Rust?
Local let like in caml
E0309: Constraining a generic type parameter's lifetime
Are nested matches a bad practice in idiomatic Rust?
Extern crate inside main method; module::Type vs main::module::Type
Iterating over named regex groups in Rust
How do I give a mutable reference to a builder but only an immutable reference to the built object?
Function returning a closure not working inside my filter
How do I get a pointer to a memory location when I know the memory address (without using std::ptr)? [duplicate]
How to expose a Rust `Vec<T>` to FFI?
RegOpenKeyExA Keeps Returning Invalid Paramater
Can not return a Chars iterator because it “does not live long enough”
Rust empty value for expression

Categories

HOME
entity-framework
plesk
operating-system
mousemove
haproxy
qooxdoo
amp
angular2-template
azure-graph-api
hystrix
fbloginview
chromecast
google-awareness
webstore
synthesis
infrared
jitsi
akka-persistence
el
candlestick-chart
substring
sipp
pyopencl
ratio
plyr
oracleforms
react-bootstrap-table
npoi
toad
xcrun
keyboard-layout
nsuserdefaults
macports
stat
game-center
vb.net-to-c#
hypothesis-test
music21
return-type
xcglogger
sonicmq
head.js
redisson
subforms
simple-schema
android-mediarecorder
glassfish-4.1
http4s
haraka
android-syncadapter
mnesia
gravatar
django-validation
opencyc
cfwheels
enaml
wso2ml
android-audiomanager
password-recovery
vs-unit-testing-framework
datagridcomboboxcolumn
rebar
nidaqmx
nachos
senchatouch-2.4
zend-search-lucene
air-native-extension
ivalueconverter
strdup
sql-view
tnt4j
indesign-server
aero
mongo-jackson-mapper
examine
xmlwriter
dojo-1.9
smartfox
tridion-2011
daap
image-formats
uploading
type-safety
motodev-studio
vows
ognl
mygeneration
tabbarcontroller
browser-based
service-factory
error-detection
parentid

Resources

Database Users
RDBMS discuss
Database Dev&Adm
javascript
java
csharp
php
android
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App