함수 오버로딩 구현하기

유감스럽게도 러스트엔 함수 오버로딩(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 + "!"
    }
}
}

ctorconstructor를 의미합니다. 이 예제에선 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));
}