我有一个特点:
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 :(得分:2)
我更多地考虑了我之前的答案,即使在多种类型的表单中,它仍然不是很令人满意,因为您需要定义所有类型A
,B
等等您要使用的任何基类实例,然后该子类只能接受每个方法的那些类型。
类型运算符(通用类型约束)看起来像是提供了更好的选项:
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
(通常写为A
,类似于二元运算符) T
,因此在编译时不应该禁止任何不适当的调用。
对于不受限制的子类(特征的伴随对象中工厂方法的良好候选者),类型T
可以根据需要设置为Any
或AnyRef
。 / p>
我注意到,我没有尝试使用它来构建具有隐式Unmarshaller
和Future
返回类型的特征的完全充实版本,这可能使正确的复杂化溶液
答案 1 :(得分: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] {
...
}
答案 2 :(得分: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
}
...
}