[%]
rust enum dispatch
익명(112.216)
2020-03-05 17:23
추천 0
trait MyTrait
{
fn call(&self);
}
struct Foo
;
struct Bar
;
impl MyTrait
for Foo
{
fn call(&self) {
println!("Called from foo");
}
}
impl MyTrait
for Bar
{
fn call(&self) {
println!("Called from bar");
}
}
fn call_trait(a
:&dyn MyTrait
) {
a
.call();
}
fn main() {
let a
= Foo
;
let b
= Bar
;
call_trait( &a
);
call_trait( &b
);
}
trait 구현자를 호출할때 generic 을 씌우지 못할 상황에 있을 경우
위 처럼 dyn 으로 호출할 수 있는데 fat pointer 로 변환되어 넘어간다
fat pointer는 함수테이블, 데이터를 가리키므로 pointer x2 사이즈이며
또한 런타임시에 필요 함수를 복사하므로 오버헤드가 크다
enum MyEnum
{
A(Foo
),
B(Bar
)
}
impl MyEnum
{
fn call(&self) {
match self {
Self::A( foo
) => foo
.call(),
Self::B( bar
) => bar
.call()
}
}
}
struct Foo
;
struct Bar
;
impl Foo
{
fn call(&self) {
println!("Called from foo");
}
}
impl Bar
{
fn call(&self) {
println!("Called from bar");
}
}
fn call_enum(a
:&MyEnum
) {
a
.call();
}
fn main() {
let a
= MyEnum
::A( Foo
);
call_enum( &a
);
let b
= MyEnum
::B( Bar
);
call_enum( &b
);
}
enum dispatch 는 당연하게도 훨씬 빠르다. trait 복잡도에 dyn dispatch 보다 10배까지 빠르다
근데 문제는 위 의 예는 매우 단순하지만 enum 의 타입과 함수가 늘어나면 그만큼 똑같은 패턴의 코드를
반복 구현해야 한다.
extern crate enum_dispatch
;
#[enum_dispatch]
enum MyEnum
{
A(Foo
),
B(Bar
)
}
#[enum_dispatch(MyEnum)]
trait MyEnumTrait
{
fn call(&self);
}
struct Foo
;
struct Bar
;
impl Foo
{
fn call(&self) {
println!("Called from foo");
}
}
impl Bar
{
fn call(&self) {
println!("Called from bar");
}
}
fn call_enum(a
:&MyEnum
) {
a
.call();
}
fn main() {
let a
= MyEnum
::A( Foo
);
call_enum( &a
);
let b
= MyEnum
::B( Bar
);
call_enum( &b
);
}
enum_dispatch 라는 proc-macro crate 를 사용하면 그 노동을 줄일 수 있다
당연하게도 enum 요소들의 함수 인터페이스는 동일해야 한다
이 crate 는 단순히 trait 에 맞춰 enum 에 단순 impl하는것이다
단점: 자동완성이 안됨
매크로니까 어쩔 수 없지
어플이면 뭐 편한대로 하면 되는데 라이브러리면 쓰는 사람 편의성도 생각해줘야해서