我想定义一个将* 2
应用于其参数的函数,该函数适用于有意义的所有类型。我尝试使用结构类型:
import scala.language.reflectiveCalls
def double[T](x: Any{def * (arg0: Int): T}) = x * 2
适用于字符串:
scala> double("a")
res85: String = aa
但不是数字:
scala> double(4)
java.lang.NoSuchMethodException: java.lang.Integer.$times(int)
at java.lang.Class.getMethod(Class.java:1778)
at .reflMethod$Method1(<console>:18)
at .double(<console>:18)
... 32 elided
编辑:通过“做我想要的”,我的意思是为现有的类型工作,例如数字和字符串,而不仅仅是我自己定义的类。
答案 0 :(得分:3)
*
被翻译为$times
,结构类型检查是否存在*
方法,但(我认为这是一个错误)将其称为内部($times
)表示)。这适用于String
,因为 $times
适用于他们。
此方法适用于名称仅包含字母的方法。
```
import scala.language.reflectiveCalls
def double[T](x: Any{def test (arg0: Int): T}) = x.test(2)
class A { def test(i: Int) = i * 10 }
class B { def test(i: Int) = i * 20 }
scala> double(new A)
res0: Int = 20
scala> double(new B)
res1: Int = 40
```
trait Multiply[A]{
def times(a: A, x: Int): A
}
implicit val MultString = new Multiply[String] { def times(a: String, x: Int) = a * x }
implicit val MultInt = new Multiply[Int] { def times(a: Int, x: Int) = a * x }
def double[T](t: T)(implicit mult: Multiply[T]) = mult.times(t, 2)
scala> double("aaaa")
res0: String = aaaaaaaa
scala> double(111)
res1: Int = 222
另请注意,结构类型使用reflection =&gt;很慢。
答案 1 :(得分:3)
您可以随时重载该方法。为了使它在REPL中起作用,你必须:paste
作为一个块。
def double(s:String):String = s * 2
def double[N](n:N)(implicit ev: Numeric[N]):N = {
import Numeric.Implicits._
n * ev.fromInt(2)
}
double("this") // result: String = thisthis
double(3L) // result: Long = 6
答案 2 :(得分:0)
我发现的另一种可能性是使用宏。从Scala 2.11.8开始,它们仍然是实验性的,according to Martin Odersky,不会以这种形式存在。当前的synax是笨拙的,但到目前为止它是唯一完全DRY的方法(* 2
只写一次,并且该函数适用于支持此操作的所有类型。)
无论这是否是最佳解决方案,我都是为了完整性而发布:
import reflect.macros.Context
def doubleImpl[T](c: Context)(x: c.Expr[T]): c.Expr[T] = {
import c.universe._
c.Expr(q"${x.tree} * 2")
}
def double[T](x: T): T = macro doubleImpl[T]