2015-09-29 129 views
1

我有一個特點:Scala類型:如何限制子類的泛型類型?

trait OAuthService { 
    def sendWithAuthorizationQueryParams[A](request: OAuthRequest)(implicit unmarshaller: Unmarshaller[ResponseEntity, A]): Future[A] = { 
    val httpRequest = request.toHttpRequestWithAuthorizationQueryParams 

    sendAndReceive(httpRequest, request.signature) 
    } 

    def sendWithAuthorizationHeader[A](request: OAuthRequest)(implicit unmarshaller: Unmarshaller[ResponseEntity, A]): Future[A] = { 
    val httpRequest = request.toHttpRequestWithAuthorizationHeader 

    sendAndReceive(httpRequest, request.signature) 
    } 

    protected def sendAndReceive[A](httpRequest: HttpRequest, id: String)(implicit unmarshaller: Unmarshaller[ResponseEntity, A]): Future[A] 
} 

我創建一個子類:

class StreamingOAuthService()(implicit val actorPlumbing: ActorPlumbing) extends OAuthService { 
    private val log = LoggerFactory.getLogger(getClass()) 

    override protected def sendAndReceive[A](httpRequest: HttpRequest, id: String)(implicit unmarshaller: Unmarshaller[ResponseEntity, A]) = { 
    log.debug(s"Http request: {}.", httpRequest) 

    import actorPlumbing._ 

    val host = httpRequest.uri.authority.host.address() 

    val connectionFlow: Flow[HttpRequest, HttpResponse, Future[OutgoingConnection]] = Http().outgoingConnectionTls(host) 

    Source.single(httpRequest) 
     .via(connectionFlow) 
     .runWith(Sink.head) 
    } 
} 

StreamingOAuthService,我想凍結泛型類型爲ResponseEntity。換句話說,我想指定StreamingOAuthService方法支持的唯一類型是ResponseEntity。如圖所示,StreamingOAuthService.sendAndReceive不會編譯,因爲返回類型是Future[ResponseEntity],而不是由性狀指定的Future[A]

回答

0

我假設你的意思是你想要類型規格A被鎖定在ResponseEntity的子類中。如果是的話,你可以嘗試將抽象類型成員的特徵和子類:

trait OAuthService { 

    type A 

    def sendWithAuthorizationQueryParams(request: OAuthRequest)(implicit unmarshaller: Unmarshaller[ResponseEntity, A]): Future[A] = { 
    ... 
    } 

    ... 
} 

class StreamingOAuthService()(implicit val actorPlumbing: ActorPlumbing) extends OAuthService { 
    private val log = LoggerFactory.getLogger(getClass()) 

    type A = ResponseEntity 

    override protected def sendAndReceive(httpRequest: HttpRequest, id: String)(implicit unmarshaller: Unmarshaller[ResponseEntity, ResponseEntity]) = { 
    ... 
    } 

    ... 
} 

注意,這個假設A需要是同一類型的一個實例中的所有方法,甚至在基本特質。

如果這不是意圖,上述想法可以擴展爲定義每種方法的類型(儘管顯然這可能會很快得到解決)。

這裏有一個(簡單的)例子給你的想法:

trait Base { 

    type A 
    type B 
    ... 

    def fun1(input: String): A 

    def fun2(input: Int): B 

    ... 
} 

class Sub extends Base { 

    type A = Double 
    type B = Double 
    ... 

    def fun1(input: String): A = { 
    input.toDouble 
    } 

    def fun2(input: Int): B = { 
    input.toDouble 
    } 

    ... 
} 
+0

仍然不滿意 - 我有第二個答案看起來更有希望,涉及類型操作符。 – Shadowlands

1

可以參數化用[A]和擺脫參數化的特質每個方法的整體特點:

trait OAuthService [A]{ 
    def sendWithAuthorizationQueryParams(request: OAuthRequest)(implicit unmarshaller: Unmarshaller[ResponseEntity, A]): Future[A] = ... 
    ... 
} 

而且然後限制StreamingOAuthService使用ResponseEntity:

class StreamingOAuthService()(implicit val actorPlumbing: ActorPlumbing) extends OAuthService[ResponseEntity] { 
... 
} 
+0

這是我考慮過的一個選項,但不喜歡它,因爲它僅將整個類鎖定爲一種類型。 –

2

我想了解一下我的伯爵ier回答,甚至在多類型的形式,它仍然不是很滿意,因爲你需要定義所有類型AB,等等基類的任何實例要使用,並且該子類只能接受每種方法的這些類型。

類型運營商(廣義類型約束)看起來像他們提供一個更好的選擇:

trait Base { 

    type T 

    def fun1[A](input: String)(implicit tp: A <:< T): A 

    def fun2[A](input: Int)(implicit tp: A <:< T): A 
} 

class RestrictedSub extends Base { 

    override type T = Double 

    def fun1[A](input: String)(implicit tp: A <:< T): A = { 
    ... 
    } 

    def fun2[A](input: Int)(implicit tp: A <:< T): A = { 
    ... 
    } 
} 

對於方法的任何呼叫,編譯器可以提供一個適當的隱式<:<[A,T](通常寫入A <:< T,類似於一個二進制運算符)當且僅當AT的子類型,因此在編譯時應禁止任何不適當的調用。

對於無限制的子類(的良好候選中該性狀的同伴對象工廠方法),類型T可以設置爲AnyAnyRef適當。

我也注意到,雖然,我沒有使用此建立自己的特質與隱性Unmarshaller S和Future返回類型,這可能複雜化的妥善解決辦法一個完全充實版本嘗試。

+0

它不編譯。我嘗試過並且沒有從你的提議中做出一點小修改,我使用'A型'來表現特性,這實際上就是'T型'所做的。 (未知):未知[B] = {...}特徵OAuthService [A] { def sendWithAuthorizationQueryParams [B](request:OAuthRequest)(implicit ev:B <:

+0

@AhhijitSarkar嗯,這是一個麻煩。用我的縮減版本在REPL中播放時沒有出現這種情況。也許你可以找到一種方法來阻止'Predef'隱式,根據答案[這裏](http://stackoverflow.com/questions/5377492/problem-with-implicit-ambiguity-between-my-method-and -conforms合PREDEF)。 – Shadowlands

+0

我開始相信蘊含是Scala的致命弱點,因爲泛型是Java的。使用類型擦除的半個Java Java泛型需要比使用它的實際代碼更多的解決方法。 –