Mic*_* W. 3 generics scala class function
我已经遇到过这个问题好几次了:
我有一个计算某些东西的函数,可以说
def square(n: Int): Int = n * n
Run Code Online (Sandbox Code Playgroud)
(非常简单的例子,但这就可以了)
然后我对另一种数据类型有相同的“算法”,可以说很长:
def square(n: Long): Long = n * n
Run Code Online (Sandbox Code Playgroud)
然后是 BigInt、Short、Byte 等。
如果我的算法比这个例子更复杂、更长,我就会有很多代码重复。
我想要的是一个通用定义,例如:
def square[T :> AnyVal](n: T): T = n * n
Run Code Online (Sandbox Code Playgroud)
但这不起作用,因为在 hirachy 类中,在 AnyVal 与 Int、Long 和 Float 之下还有 Boolean 和 Unit。对于布尔值和单位,术语 n * n 没有意义,我得到一个编译器错误(正确)。
我只希望我的函数适用于“可计算”数据类型,如 Int、Long、Float...,它们具有所有常见的数学运算符,如 +、*、/、< 等,然后用此制定我的算法或计算一次性为所有操作员提供服务。
当然,我可以匹配函数输入变量 n,然后以不同的方式处理每种情况,但我也会像之前一样通过重载重复所有代码。
我尝试创建自己的特征“Computables”,然后扩展到其他类 Int、Long 等,但编译器抱怨“...无法扩展最终类 Int”
这可能吗?我错过了什么吗?
您可以使用该Numeric特征:
def square[T](n: T)(using numeric: Numeric[T]): T = numeric.times(n,n)
Run Code Online (Sandbox Code Playgroud)
或者
def square[T](n: T)(using numeric: Numeric[T]): T = {
import numeric._
n * n
}
Run Code Online (Sandbox Code Playgroud)
我想,你正在寻找一个类型类
Numeric另一个答案中提到的是描述所有数字类型的类型类的示例。但你可以概括它来描述任何类型的行为。
查看我上面提到的链接,它有详细信息和示例,但从总体上讲,其想法是这样的:
def someFunction[T : SomeType](t: T)相当于def someFunction[T](t: T)(implicit ev: SomeType[T])
这意味着像
val foo: Foo = ???
someFunction(foo)
Run Code Online (Sandbox Code Playgroud)
当且仅当您在范围内某处有类型的隐式实例时才会编译SomeType[Foo]。
因此,这解决了问题的第一部分:我们Numeric为所有“数字”类型定义了实例,但没有为字符串或布尔值定义实例,因此通过这种方式,您可以将可以发送到函数的类型限制为特定的“类”类型的”(即“类型类”)。
类型类的另一个目的是表达它所包含的类型的常见行为。您可以“召唤”类型类的隐式“证据”来访问它:
def someFunction[T : SomeType](t: T) = implicitly[SomeType[T]].doStuff(t)
Run Code Online (Sandbox Code Playgroud)
在你的情况下,使用square:
def square[T : Numeric](t: T) = implicitly[Numeric[T]].times(t, t)
Run Code Online (Sandbox Code Playgroud)