2015-09-29 127 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泛型需要比使用它的实际代码更多的解决方法。 –