[SCALA] 어떻게 문맥에 관련한 타입 클래스의 인스턴스 바인딩을받을 수 있나요?
SCALA어떻게 문맥에 관련한 타입 클래스의 인스턴스 바인딩을받을 수 있나요?
참고 : 내가 직접 대답이 질문에 포즈를하고있어,하지만 다른 답변을 환영합니다.
다음과 같은 간단한 방법을 고려 :
def add[T](x: T, y: T)(implicit num: Numeric[T]) = num.plus(x,y)
나는 다음과 같이 바인딩 컨텍스트를 사용하여 다시 작성할 수 있습니다
def add[T: Numeric](x: T, y: T) = ??.plus(x,y)
하지만 어떻게 숫자 [T]의 인스턴스 내가 플러스 메소드를 호출 할 수 있도록 입력받을 수 있나요?
해결법
-
==============================
1.암시 적 방법을 사용하여
암시 적 방법을 사용하여
가장 일반적이고 일반적인 접근 방식은 PREDEF에 정의 된 암시 적 방법을 사용하는 것입니다 :
def add[T: Numeric](x: T, y: T) = implicitly[Numeric[T]].plus(x,y)
분명히, 이것은 다소 장황하고 타입 클래스의 이름을 반복해야합니다.
증거 매개 변수를 참조하는 (하지 않습니다!)
또 다른 대안은 자동으로 컴파일러에 의해 생성 된 암시 적 증거 매개 변수의 이름을 사용하는 것입니다 :
def add[T: Numeric](x: T, y: T) = evidence$1.plus(x,y)
이 기술은 심지어 합법적 것은 놀라운 일이고, 그것은 변경 될 수 있습니다 증거 매개 변수의 이름부터 연습에 의존해서는 안됩니다.
고등 종류의 컨텍스트 (문맥 도입 방법)
대신에, 하나는 암시 적 방법의 강화 된 버전을 사용할 수 있습니다. 암시 적 방법은 다음과 같이 정의되어 있습니다
def implicitly[T](implicit e: T): T = e
이 방법은 단순히 메소드 호출로 주변 범위에서 올바른 유형의 암시 적 개체를 삽입하는 컴파일러에 의존하고 돌려줍니다. 우리는 더 나은 약간의 작업을 수행 할 수 있습니다
def context[C[_], T](implicit e: C[T]) = e
이것은 우리의 add 메소드를 정의 할 수있게 해준다
def add[T: Numeric](x: T, y: T) = context.plus(x,y)
문맥에있어서 타입 파라미터 T는 숫자 및 범위로부터 추론! 불행하게도,이 상황에 맞는 방법이 작동하지 않습니다하는 경우가있다. 타입 파라미터는 여러 문맥 범위를 갖거나 다른 컨텍스트 경계 여러 파라미터들은 예를 들면, 존재하는 경우. 우리는 조금 더 복잡한 버전으로 후자의 문제를 해결할 수 있습니다 :
class Context[T] { def apply[C[_]]()(implicit e: C[T]) = e } def context[T] = new Context[T]
이 버전마다 매개 변수 유형을 지정하기 위해 우리를 필요로하지만, 여러 유형 매개 변수를 처리합니다.
def add[T: Numeric](x: T, y: T) = context[T]().plus(x,y)
-
==============================
2.스칼라 2.9 이후 적어도 다음을 수행 할 수 있습니다 :
스칼라 2.9 이후 적어도 다음을 수행 할 수 있습니다 :
import Numeric.Implicits._ def add[T: Numeric](x: T, y: T) = x + y add(2.8, 0.1) // res1: Double = 2.9 add(1, 2) // res2: Int = 3
-
==============================
3.이 답변은 다른 접근 방식을 설명하는 더 읽을 수있는, 자기 문서화 클라이언트 코드의 결과.
이 답변은 다른 접근 방식을 설명하는 더 읽을 수있는, 자기 문서화 클라이언트 코드의 결과.
동기
내가 설명하는 문맥 방법은 이전에 별도의 노력없이, 모든 종류의 클래스로 작동하는 매우 일반적인 솔루션입니다. 그러나, 그것은 두 가지 이유로 바람직하지 않을 수 :
타입 클래스 고유의 방법
원하는 타입 클래스 차종 클라이언트 코드에 더 많은 읽을 수 연결하는 방법을 사용. 이 매니페스트 타입 클래스의 표준 라이브러리에서 사용하는 방법입니다 :
// definition in Predef def manifest[T](implicit m: Manifest[T]) = m // example usage def getErasure[T: Manifest](x: T) = manifest[T].erasure
이 방법을 일반화
타입 급 전용 방법을 사용하는 주요 단점은 부가적인 방법은 모든 종류의 클래스 정의되어야한다는 것이다. 우리는 다음과 같은 정의에이 과정을 쉽게 할 수 있습니다 :
class Implicitly[TC[_]] { def apply[T]()(implicit e: TC[T]) = e } object Implicitly { def apply[TC[_]] = new Implicitly[TC] }
그런 다음 새로운 유형의 클래스 별 암시 적 스타일의 방법은 모든 종류의 클래스, 정의 할 수 있습니다 :
def numeric = Implicitly[Numeric] // or val numeric = Implicitly[Numeric]
마지막으로 다음과 같이, 클라이언트 코드는 암시를 사용할 수 있습니다 :
def add[T: Numeric](x: T, y: T) = numeric[T].plus(x, y)
from https://stackoverflow.com/questions/4373070/how-do-i-get-an-instance-of-the-type-class-associated-with-a-context-bound by cc-by-sa and MIT license
'SCALA' 카테고리의 다른 글
[SCALA] 스칼라에서 반복자 및 스트림의 차이? (0) | 2019.11.15 |
---|---|
[SCALA] 스칼라 : VAR-인수 기능에 패스 서열 (0) | 2019.11.15 |
[SCALA] 스칼라 : 케이스 클래스로 변환지도 (0) | 2019.11.15 |
[SCALA] 어떻게 다른 SBT 프로젝트에서 외부 SBT 프로젝트를 참조하는? (0) | 2019.11.15 |
[SCALA] Groovy의 안전 참조 연산자 최고의 스칼라 모방 (?).? (0) | 2019.11.15 |