Go는 generics 혹은 parametric polymorphism 을 지원하지 않아서 generic collection 같은 걸 만들기가 어렵다.
container/list 패키지를 보면 아래처럼 interface{} 타입을 써서 어떤 값이든 담을 수 있게 했다.
sort 패키지를 보면 1) 크기 비교 가능하고, 2) 랜덤 액세스를 통해 swap 연산이 되며, 3) 전체 길이가 알려진 경우를 인터페이스로 정의하여 정렬 알고리즘을 일반화하였다.
이 경우는 interface{} 타입을 사용하는대신 '인덱스'만으로 알고리즘을 전개할 수 있게 했다.
대개 다른 언어들이 '비교 가능한 요소'들을 대상으로 비교 함수가 만들어지는데, 인덱스를 사용한 것이 특이하다. 비교 함수를 뒤집어서 역순 정렬을 하려면?
Reverse 함수로 interface 값을 한번더 래핑하면 된다.
Reverse 함수의 반환값을 보면 &reverse{data} 인데, 여기서 data 도 sort.Interface 타입이고함수의 반환타입 역시 sort.Interface다. (즉, sort.reverse 구조체는 decorator 나 wrapper 같은 역할을 한다.)
여기서 특이한 점은, 1) Reverse 함수가 왜 포인터를 반환하느냐? 2) Less 메쏘드의 리시버 타입은 왜 밸류 타입인가?
사실 Reverse 함수를 밸류로 반환해도, 이미 reverse 구조체가 sort.Interface 인터페이스를 구현하기 때문에 (임베드하면서 Less만 오버라이드) 정렬 기능에는 문제가 없다. 혹은, 포인터를 반환하여 (sort.Interface로) 래핑하기 때문에 Less 함수의 리시버가 *reverse 타입이어도 문제없다.
왜 이것도 되고, 저것도 되는데 위의 모양을 가지게 되었을까?
추측컨데,
1) Reverse 함수의 반환 값이 인터페이스이므로 포인터를 반환함으로써 어떠한 리시버도 가능할 뿐 아니라 인터페이스 값을 만드는 비용이 저렴하다.
2) Less 메쏘드는 리시버 (reverse 구조체) 내부를 건드리지 않는다. 즉, 포인터를 사용할 이유가 없는 것이다. (만일 메쏘드 리시버가 밸류로 선언되어 호출 시 리시버 값이 복사되는 것이 부담된다면 포인터 타입으로 리시버를 사용할 수 있겠지만 reverse 구조체는 sort.Interface 인터페이스만 임베드하고 있어서 two-word 크기를 가진다. 복사 비용이 부담되지 않으므로 일부러 포인터 타입의 리시버로 정의할 필요가 없다.
container/list 패키지를 보면 아래처럼 interface{} 타입을 써서 어떤 값이든 담을 수 있게 했다.
sort 패키지를 보면 1) 크기 비교 가능하고, 2) 랜덤 액세스를 통해 swap 연산이 되며, 3) 전체 길이가 알려진 경우를 인터페이스로 정의하여 정렬 알고리즘을 일반화하였다.
이 경우는 interface{} 타입을 사용하는대신 '인덱스'만으로 알고리즘을 전개할 수 있게 했다.
대개 다른 언어들이 '비교 가능한 요소'들을 대상으로 비교 함수가 만들어지는데, 인덱스를 사용한 것이 특이하다. 비교 함수를 뒤집어서 역순 정렬을 하려면?
Reverse 함수로 interface 값을 한번더 래핑하면 된다.
Reverse 함수의 반환값을 보면 &reverse{data} 인데, 여기서 data 도 sort.Interface 타입이고함수의 반환타입 역시 sort.Interface다. (즉, sort.reverse 구조체는 decorator 나 wrapper 같은 역할을 한다.)
여기서 특이한 점은, 1) Reverse 함수가 왜 포인터를 반환하느냐? 2) Less 메쏘드의 리시버 타입은 왜 밸류 타입인가?
사실 Reverse 함수를 밸류로 반환해도, 이미 reverse 구조체가 sort.Interface 인터페이스를 구현하기 때문에 (임베드하면서 Less만 오버라이드) 정렬 기능에는 문제가 없다. 혹은, 포인터를 반환하여 (sort.Interface로) 래핑하기 때문에 Less 함수의 리시버가 *reverse 타입이어도 문제없다.
왜 이것도 되고, 저것도 되는데 위의 모양을 가지게 되었을까?
추측컨데,
1) Reverse 함수의 반환 값이 인터페이스이므로 포인터를 반환함으로써 어떠한 리시버도 가능할 뿐 아니라 인터페이스 값을 만드는 비용이 저렴하다.
2) Less 메쏘드는 리시버 (reverse 구조체) 내부를 건드리지 않는다. 즉, 포인터를 사용할 이유가 없는 것이다. (만일 메쏘드 리시버가 밸류로 선언되어 호출 시 리시버 값이 복사되는 것이 부담된다면 포인터 타입으로 리시버를 사용할 수 있겠지만 reverse 구조체는 sort.Interface 인터페이스만 임베드하고 있어서 two-word 크기를 가진다. 복사 비용이 부담되지 않으므로 일부러 포인터 타입의 리시버로 정의할 필요가 없다.
댓글 없음:
댓글 쓰기