Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 使用无法隐式转换的参数定义方法_Scala - Fatal编程技术网

Scala 使用无法隐式转换的参数定义方法

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

我试图定义一个方法,该方法只接受一个参数,该参数必须是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?

我不确定您隐式转换参数的问题是什么,我的建议是对此保持平静,但这里有一个可能对您有用的选项:

您可以使用类型类模式定义类型上下文:

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-检查