2016-10-23 3 views
0

지도 정의의 일부로 전달되는 제네릭 형식을 사용하는 함수를 사용하려고합니다. 여기클래스를 확장하는 일반 유형이있는 함수

내 코드

object EventMapping { 


    val eventMapping = collection.mutable.Map[Class[_ <: EventBase], (User, EventBase) => Unit]() 

    setMapping(classOf[UserCreated], (user, evt) => user.loadUserName(evt.userName)) 


    private def setMapping[T <: EventBase](clazz: Class[T],fn: (User, T) => Unit) { 
    eventMapping += clazz -> fn.asInstanceOf[(User, EventBase) => Unit] 
    } 

} 

사용자 생성 클래스 인 EN 이벤트 setMapping에서 나는 T를 정의하기 때문에 EventBase에서 확장 그래서, EventBase에서 확장 클래스 및 setMapping 호출 미안 정의 클래스 타입 I에서 나는 그것이 될 것이라고 EVT는 CreatedUser 이벤트로 생각 기다리고 있었다 기능

user.loadUserName(evt.userName)) 

에 사용하지만, 여전히 컴파일러는 EventBase으로 고려하고있다.

Java에서 비슷한 코드 기반이 작동하지만 여기에 무엇이 누락되어 있는지 모르겠습니다. 여기

이 스택 트레이스

[info] Compiling 5 Scala sources to /Development/proyectX/target/scala-2.11/classes... 
[error] /Development/proyectX/app/persistance/EventMapping.scala:11: missing parameter type 
[error] setMapping(classOf[UserCreated], (user, evt) => user.loadUserName(evt.asInstanceOf[UserCreated].userName)) 
[error]           ^
[error] one error found 
[error] (compile:compile) Compilation failed 
+0

무엇이 오류입니까? 컴파일러 오류 메시지를 게시 할 수 있습니까? – Yawar

+0

스택 추적을 추가합니다 – paul

답변

3

문제는 setMapping의 정의에, 컴파일러 해당 T을 이야기한다는 것이다에게 있습니다

class UserCreated @JsonCreator() (@JsonProperty("userName")val userName: String) extends EventBase{ 


    @JsonProperty("userName") def getUserName: String = { 
    userName 
    } 
} 

사용자 생성 클래스는 EventBase의 하위 유형입니다 . 따라서 setMapping을 호출 할 때 evt.userName을 호출하면 컴파일러에서 EventBase의 모든 하위 유형이 userName 멤버를 지원한다는 보장을 할 수 없으므로 컴파일 오류가 발생합니다. 따라서 evt.asInstanceOf[UserCreated].userName을 수행 할 때 컴파일러는 evt이 실제로 UserCreated이고 userName 멤버를 지원함을 보장합니다.

둘째, missing parameter type 컴파일 오류 (안 스택 추적 BTW, 흔적 런타임 예외에서만 있습니다 스택은) 스칼라의 타입 추론 알고리즘이 완벽하게되지 않는 결과입니다. 지금 컴파일러가 추론 할 수 있기 때문에 이것은 또한 evt.asInstanceOf[UserCreated]를 다운 캐스트 할 필요성을 제거합니다

object EventMapping { 
    val eventMapping = 
    collection.mutable.Map[Class[_ <: EventBase], (User, EventBase) => Unit]() 

    setMapping(classOf[UserCreated]) { (user, evt) => 
    user.loadUserName(evt.userName) 
    } 

    private def setMapping[T <: EventBase](
    clazz: Class[T])(fn: (User, T) => Unit): Unit = 
    eventMapping += clazz -> fn.asInstanceOf[(User, EventBase) => Unit] 
} 

: 알고리즘의 특질의 때문에, 당신은 자신의 매개 변수 목록에 매핑 기능 (fn)를 이동하여 더 정확하게 할 수 있습니다 그것 제대로.

마지막으로 때로는 유형 추론 기가 모든 것을 올바르게 나열 할 수없고 컴파일 오류가 발생하는 경우가 있습니다. 이 경우 당신은 명시 적으로 형식 인수를 전달할 수 있습니다

setMapping[UserCreated](classOf[UserCreated]) { (user, evt) => 
    user.loadUserName(evt.userName) 
} 

이것은 UserCreated와 그 대체이 호출에 사방이 제네릭 타입 T이 컴파일러를 알려줍니다.

P. 당신이 다운 캐스팅해야만한다는 사실은 일반적으로 더 관용적이며 구성 가능한 Scala 기능인 typeclass를 사용할 수 있다는 신호입니다.

+0

그게 내가 놓친 핵심이었다 [UserCreated] 고마워! – paul

관련 문제