前提
rustc 1.22.1
本題
traitを書く時、こういう書き方はできない。
trait Horizontal {
fn count_up (&mut self) -> i64 {
self.x += 1;
self.x
}
}
struct Point {
x: i64,
}
impl Horizontal for Point {}
前提としてtraitのデフォルト実装はフィールドに干渉できない。
Traitを実装したStructに特定のフィールドを強制したい場合、
例えば、getter/setterの定義を用意することで実現できる。
trait Horizontal {
fn get_x (&self) -> i64;
fn set_x (&mut self, val: i64);
fn count_up (&mut self) {
let next = self.get_x() + 1;
self.set_x( next );
self.get_x()
}
}
struct Point {
x: i64,
}
impl Horizontal for Point {
fn get_x (&self) -> i64 {
self.x
}
fn set_x (&mut self, val: i64) {
self.x = val;
}
}
余談: getter/setterのマクロを書いてみた
traitで使うaccessor
と、実装時に使うaccessor_impl
macro_rules! accessor {
((get=$getter:ident) : $type:ty ) => {
fn $getter(&self) -> $type ;
};
((set=$setter:ident) : $type:ty ) => {
fn $setter(&mut self, value:$type) ;
};
((get=$getter:ident, set=$setter:ident) : $type:ty ) => {
accessor!((get=$getter): $type);
accessor!((set=$setter): $type);
};
}
macro_rules! accessor_impl {
((get=$getter:ident) $name:ident : $type:ty ) => {
fn $getter(&self) -> $type {
self.$name
}
};
((set=$setter:ident) $name:ident : $type:ty ) => {
fn $setter(&mut self, value: $type) {
self.$name = value;
}
};
((get=$getter:ident, set=$setter:ident) $name:ident : $type:ty ) => {
accessor_impl!((get=$getter) $name:$type);
accessor_impl!((set=$setter) $name:$type);
};
}
このマクロを使うとこんな感じになる。フィールドが増えないと効き目が薄い。
trait Horizontal {
accessor!((get = get_x, set = set_x): i64);
fn count_up(&mut self) -> i64 {
let next = self.get_x() + 1;
self.set_x(next);
self.get_x()
}
}
struct Point {
x: i64,
}
impl Horizontal for Point {
accessor_impl!((get = get_x, set = set_x) x: i64);
}