Scala 使用无法隐式转换的参数定义方法
我试图定义一个方法,该方法只接受一个参数,该参数必须是a类型,并且没有隐式转换Scala 使用无法隐式转换的参数定义方法,scala,Scala,我试图定义一个方法,该方法只接受一个参数,该参数必须是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 detail
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?我不确定您隐式转换参数的问题是什么,我的建议是对此保持平静,但这里有一个可能对您有用的选项: 您可以使用类型类模式定义类型上下文:
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
注意:如果对类型进行注释,隐式转换仍将生效
我不确定您隐式转换参数的问题是什么,我的建议是和平解决这个问题,但这里有一个可能对您有用的选项: 您可以使用类型类模式定义类型上下文:
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
注意:如果对类型进行注释,隐式转换仍将生效
正如stew所指出的,您对=:=的使用是不正确的 下面是一个正确的方法来完成您尝试的操作:
def g[A](x: A)(implicit e: A =:= Int) = x
与更明显的def gx:Int=x相比,这样声明g的优点在于,在对x参数进行类型检查之后,通过查找适当的隐式值,最后检查参数是否为类型A。并且,当类型检查x时,完全没有关于确切预期类型的信息,因此隐式转换无法启动:
scala> g("123")
<console>:13: error: Cannot prove that String =:= Int.
g("123")
^
scala> g(123)
res1: Int = 123
正如stew所指出的,您对=:=的使用是不正确的 下面是一个正确的方法来完成您尝试的操作:
def g[A](x: A)(implicit e: A =:= Int) = x
与更明显的def gx:Int=x相比,这样声明g的优点在于,在对x参数进行类型检查之后,通过查找适当的隐式值,最后检查参数是否为类型A。并且,当类型检查x时,完全没有关于确切预期类型的信息,因此隐式转换无法启动:
scala> g("123")
<console>:13: error: Cannot prove that String =:= Int.
g("123")
^
scala> g(123)
res1: Int = 123
如果您有一个带有单个参数的泛型方法,除非您显式指定该类型,否则将始终使用参数类型调用该方法,而不进行任何隐式转换
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
^
这可用于定义不允许强制或隐式转换的运算符:
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
^
如果您有一个带有单个参数的泛型方法,除非您显式指定该类型,否则将始终使用参数类型调用该方法,而不进行任何隐式转换
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
^
这可用于定义不允许强制或隐式转换的运算符:
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
^
您没有声明f接受类型a的参数,而是声明它接受类型a=:=a的参数。这是在要求提供证据,证明对于某些类型a,它与a的类型相同,并且始终为真。您可以将其声明为def[A]x:Aimplicit ev:A=:=A=evx,但这并不是您想要的。A总是与A相同的类型,所以这没有做任何事情,它仍然允许隐式转换发生,就像def[A,B]x:Aimplicit ev:B=:=A=evx我不确定你想做的事情是否可能你可以用宏来做类似的事情,但我不建议。你为什么需要避免隐式转换?@TravisBrown-你为什么建议反对使用宏?@daynyth-检查你没有声明f来接受类型A的参数,您声明它接受类型为a=:=a的参数。这是在要求提供证据,证明对于某些类型a,它与a的类型相同,并且始终为真。您可以将其声明为def[A]x:Aimplicit ev:A=:=A=evx,但这不是goi
你想干什么就干什么。A总是与A相同的类型,所以这没有做任何事情,它仍然允许隐式转换发生,就像def[A,B]x:Aimplicit ev:B=:=A=evx我不确定你想做的事情是否可能你可以用宏来做类似的事情,但我不建议。为什么你需要避免隐式转换?@TravisBrown-为什么你建议不使用宏?@daynyth-检查