我尝试定义一个方法,该方法接受一个必须是A
类型的参数而没有隐式转换。
scala> def f[A](x: A =:= A) = x
f: [A](x: =:=[A,A])=:=[A,A]
为了说明我的观点,以下是不可接受的:
scala> implicit def stringToInt(x: String) = x.toInt
warning: there was one feature warning; re-run with -feature for details
stringToInt: (x: String)Int
scala> def g(x: Int) = x
g: (x: Int)Int
scala> g("5")
res5: Int = 5
但是,当我尝试拨打f
时,我收到错误:
scala> f(100)
<console>:15: error: type mismatch;
found : Int(100)
required: =:=[?,?]
f(100)
^
如何更正f
?
答案 0 :(得分:4)
正如炖菜所指出的,您对=:=
的使用不正确。
以下是您尝试执行此操作的正确方法:
def g[A](x: A)(implicit e: A =:= Int) = x
像这样声明g
(在更明显的def g(x: Int) = x
上)的优点(在你的情况下)是参数是A
类型的检查最后完成(通过在x
参数已被类型检查后,查找适当的隐式值)。并且鉴于在类型检查x
时,根本没有关于确切预期类型的信息,隐式转换无法启动:
scala> g("123")
<console>:13: error: Cannot prove that String =:= Int.
g("123")
^
scala> g(123)
res1: Int = 123
但是,请注意(如Sascha Kolberg已经提到的),调用者仍然可以明确指定A
,允许隐式转换应用:
scala> g[Int]("123")
res1: Int = 123
scala> g("123":Int)
res2: Int = 123
答案 1 :(得分:2)
我不确定你的隐含转换论证的问题是什么,我的建议是与此达成和平,但这里有一个可能对你有用的选项:
您可以使用类型类模式来定义类型上下文:
trait TypeEvidence[A]
object TypeEvidence {
implicit object IntEv extends TypeEvidence[Int]
implicit object LongEv extends TypeEvidence[Long]
implicit object FloatEv extends TypeEvidence[Float]
implicit object DoubleEv extends TypeEvidence[Double]
}
然后,您可以将函数参数限制为可用的上下文:
object Foo {
def getValue[A : TypeEvidence](a: A): Int = 1
}
现在,这个函数只接受scala编译器找到与上下文绑定匹配的隐式类型的参数。
implicit def s2i(in: String): Int = Integer.parseInt(in)
Foo.getValue(100) | -> 1
Foo.getValue("100") | -> compile error: could not find implicit value for evidence parameter
注意:如果您注释了类型,隐式转换仍将启动。
Foo.getValue[Int]("100") | -> 1
答案 2 :(得分:1)
如果您有一个带有单个参数的泛型方法,除非您明确指定类型,否则将使用参数类型调用始终而不进行任何隐式转换,
def foo[A](x: A): A = x
val x = foo(1) // will be of type Int
val y = foo[Long](1) // will use Int => Long conversion and be of type Long
如果您的方法包含 两个 参数,则情况会有所不同。对于下面的方法,数字强制将由编译器完成,编译器将找到一个公共类型。
def same[A](x: A, y: A) = x == y
foo(1, 1L) // works. coercion from int to long
foo(1, spire.math.Rational(1)) // A will be inferred to Any
如果你不想允许数字强制或任何,一种方法是将这些类型分开,但要求证明它们是相同的,如下所示:
def same[A, B](x: A, y: B)(implicit ev: A =:= B) = x == y
这只有在x和y确实属于同一类型时才有效,忽略强制和隐式转换:
scala> same(1, 1L)
<console>:15: error: Cannot prove that Int =:= Long.
same(1, 1L)
scala> implicit def stringToInt(x: String) = x.toInt
stringToInt: (x: String)Int
scala> same("1", 1)
<console>:16: error: Cannot prove that String =:= Int.
same("1", 1)
^
这可用于定义不允许强制转换或隐式转换的运算符:
scala> implicit class NoCoercionEq[T](val lhs: T) { def ===[U](rhs:U)(implicit ev: T =:= U) = lhs == rhs }
defined class NoCoercionEq
scala> 1 === 1
res9: Boolean = true
scala> 1L === 1
<console>:21: error: Cannot prove that Long =:= Int.
1L === 1
^