Ответ 1
M => String
на самом деле a Function1[M, String]
. Если вы посмотрите на определение:
trait Function1[-T1, +R]
Итак, M
становится контравариантным, что означает, что для M1 >: M2
, Function1[M1, String] <: Function1[M2, String]
, скажем, M1 = Any
, тогда Function1[Any, String] <: Function1[Marker, String]
.
И вход doesntWork
- f
также контравариантен, что означает, что вы можете передать что-то меньшее, чем M => String
, и, как я только что показал, Any => String
меньше, чем Marker => String
, поэтому он пассисс полностью прекрасен.
Вы также можете передать String => String
из-за своего [M <: Marker]
, что, наконец, побуждает компилятор интерпретировать M
как Nothing
, поэтому даже String => String
становится больше, чем M => String
.
Чтобы решить вашу проблему, просто введите оболочку, которая сделает ваш тип инвариантным:
scala> case class F[M](f: M => String)
defined class F
scala> def doesntWork[M <: Marker](f:F[M]):String = "doesn't matter"
doesntWork: [M <: Marker](f: F[M])String
scala> doesntWork(F((str: String) => "a string"))
<console>:18: error: inferred type arguments [String] do not conform to method doesntWork type parameter bounds [M <: Marker]
doesntWork(F((str: String) => "a string"))
^
<console>:18: error: type mismatch;
found : F[String]
required: F[M]
doesntWork(F((str: String) => "a string"))
^
scala> doesntWork(F((str: Any) => "a string"))
<console>:18: error: inferred type arguments [Any] do not conform to method doesntWork type parameter bounds [M <: Marker]
doesntWork(F((str: Any) => "a string"))
^
<console>:18: error: type mismatch;
found : F[Any]
required: F[M]
Note: Any >: M, but class F is invariant in type M.
You may wish to define M as -M instead. (SLS 4.5)
doesntWork(F((str: Any) => "a string"))
scala> doesntWork(F((str: Marker) => "a string"))
res21: String = doesn't matter
scala> trait Marker2 extends Marker
defined trait Marker2
scala> doesntWork(F((str: Marker) => "a string"))
res22: String = doesn't matter
scala> doesntWork(F((str: Marker2) => "a string"))
res23: String = doesn't matter
Как правило, плохо рекомендовать такие неявные преобразования, но здесь кажется прекрасным (если вы не будете злоупотреблять f
):
scala> implicit def wrap[M](f: M => String) = F(f)
warning: there was one feature warning; re-run with -feature for details
wrap: [M](f: M => String)F[M]
scala> doesntWork((str: Marker) => "a string")
res27: String = doesn't matter
scala> doesntWork((str: String) => "a string")
<console>:21: error: inferred type arguments [String] do not conform to method doesntWork type parameter bounds [M <: Marker]
doesntWork((str: String) => "a string")
^
<console>:21: error: type mismatch;
found : F[String]
required: F[M]
doesntWork((str: String) => "a string")
^