함수 오버로딩 구현하기
유감스럽게도 러스트엔 함수 오버로딩(overloading
), default parameter
, optional parameter
등이 없습니다.
하지만 오버로딩은 대충 구현해볼 수 있습니다:
#![allow(unused)] fn main() { struct Overloading; trait Foo<T> { type Output; fn ctor(arg: T) -> Self::Output; } }
이렇게 선언된 구조체와 트레잇을 이용하여 함수 오버로딩을 사용할 수 있습니다:
#![allow(unused)] fn main() { impl Foo<usize> for Overloading { type Output = usize; fn ctor(arg: usize) -> Self::Output { arg * 10 } } impl Foo<String> for Overloading { type Output = String; fn ctor(arg: String) -> Self::Output { arg + "!" } } }
ctor
은constructor
를 의미합니다. 이 예제에선ctor
라는 네이밍을 사용했습니다.
이런 식으로 제네릭 T
엔 인자 타입, 연관 타입(associated type) Output
을 구현하여, 오버로딩을 흉내 낼 수 있습니다.
이제 헬퍼(Helper) 함수를 이용해서 편리하게 호출할 수 있습니다:
#[inline] fn foo<T>(arg: T) -> <Overloading as Foo<T>>::Output where Overloading: Foo<T>, { <Overloading as Foo<T>>::ctor(arg) } fn main() { println!("{}", foo(2)); println!("{}", foo(String::from("Hello"))); }
번외로, 여기서 #[inline]
속성이 사용되었습니다. 이에 대한 글은 이곳을 참고해봅시다.
다만 복수 개의 인자를 받을 수는 없습니다. 그럴땐 튜플을 사용하거나 매크로를 사용해봅시다:
#![allow(unused)] fn main() { impl Foo<(usize, usize)> for Overloading { type Output = usize; fn ctor(arg: (usize, usize)) -> Self::Output { arg.0 + arg.1 } } println!("{}", foo((2, 3))); }
#![allow(unused)] fn main() { macro_rules! foo { ($arg:expr) => { $arg * 10 }; ($a:expr, $b:expr) => { $a + $b }; } assert_eq!(foo!(2), foo!(15, 5)); }