Kotlin - не могу вывести тип generi c - PullRequest
1 голос
/ 09 февраля 2020

Я работаю с шаблоном ask Акки в Kotlin, и я столкнулся с проблемой ковариации. Вот ситуация:

interface Token {
  // arbitrary stuff
}

class SpecificToken(override val underlying: TokenFound) : Token, ArbitraryInterface<TokenFound> {
  // arbitrary stuff
}

interface TokenRepository {
  fun find(): CompletionStage<Token?>
}

class SpecificTokenRepository : TokenRepository {

  val actor1 = getActor1()
  val actor2 = getActor2()
  val message1 = getMessage1()
  val message2 = getMessage2()
  val timeout = getTimeout()

  fun find(): CompletionStage<Token?> = 
    inquire().thenCompose {
      when (it) {
        is Inquiry -> Patterns.ask(actor, message, timeout)
          .handle { response, t -> 
            handleExceptions(t)
            if (response is TokenFound) SpecificToken(response) else null
          }
        else -> CompletableFuture.completedFuture(null)
      }

   fun inquire(): CompletionStage<Inquiry?> = 
     Patterns.ask(actor, message, timeout)
       .handle { response, t ->
         handleExceptions(t)
         if (response is Inquiry) response else null
       }
}

Проблема здесь в том, что thenCompose имеет проблему с обобщением Java, которое я предполагаю, читая:

Type inference failed: Cannot infer type parameter U in 
fun <U : Any!> thenCompose
(fn: ((t: Inquiry?) → CompletionStage<U!>!)!): CompletionStage<U!>!
None of the following substitutions

(((Inquiry?) → CompletionStage<Token?>!)!)    

(((Inquiry?) → CompletionStage<SpecificToken?>!)!)

(((Inquiry?) → CompletionStage<Nothing!>!)!)

can be applied to

((Inquiry?) → CompletionStage<out SpecificToken?>!)

Что необходимо изменить здесь и, если возможно, не могли бы вы объяснить, почему? Спасибо!

Ответы [ 2 ]

1 голос
/ 10 февраля 2020

Очевидно (и очевидно), значения null должны быть приведены к типу Token?, поэтому изменение функции на

fun find(): CompletionStage<Token?> = 
  inquire().thenCompose {
    when (it) {
      is Inquiry -> Patterns.ask(actor, message, timeout)
        .handle { response, t -> 
          handleExceptions(t)
          if (response is TokenFound) SpecificToken(response) else null as Token?
        }
      else -> CompletableFuture.completedFuture<Token?>(null)
    }

решает проблему.

0 голосов
/ 10 февраля 2020

Пока вы нашли решение, я думаю, что стоит объяснить, почему оно необходимо.

if (response is TokenFound) SpecificToken(response) else null равно SpecificToken?, поэтому ветвь Patterns.ask(actor, message, timeout).handle { ... } имеет тип CompletableFuture<SpecificToken?>.

null само по себе имеет тип Nothing?, поэтому CompletableFuture.completedFuture(null) равно CompletableFuture<Nothing?>.

Поскольку ваши две ветви заканчиваются разными типами, у всего выражения when(it) { ... } есть общий супертип - CompletableFuture<out SpecificToken?>.

...