算术scala是:
package Arithmetic
// The Arithmetic typeclass which implements various arithmetic operations on custom datatypes
abstract class Arithmetic[T <: Data] {
implicit def cast(t: T): ArithmeticOps[T]
}
abstract class ArithmeticOps[T <: Data](self: T) {
def *(t: T): T
def mac(m1: T, m2: T): T // Returns (m1 * m2 + self)
def +(t: T): T
...
}
object Arithmetic {
implicit object UIntArithmetic extends Arithmetic[UInt] {
override implicit def cast(self: UInt) = new ArithmeticOps(self) {
...
}
implicit object SIntArithmetic extends Arithmetic[SInt] {
override implicit def cast(self: SInt) = new ArithmeticOps(self) {
...
}
}
在另一个scala文件中:
import Arithmetic._
class PE[T <: Data](inputType: T, ...)(implicit ev: Arithmetic[T]) extends Module {
import ev._
...
}
我问题是:
1.一个抽象类可以有一个伴随对象吗?(如Arithmetic)
1.我知道有一些隐式转换。让我困惑的是,当我使用import Arithmetic._
时,ev
指的是什么?伴随对象还是抽象类?
1条答案
按热度按时间nbnkbykc1#
首先,关于如果已经有一个trait/class
Arithmetic
,我们是否可以定义一个对象Arithmetic
:是的。2有两种独立的名字:类型名和值名。抽象类声明和特征声明,如引入一个名为
Arithmetic
的 * named type *。伴随对象声明引入了一个 * 值名称 *
Arithmetic
。类型名称和值名称位于不同的领域中,不会发生冲突。如果
Foobar[X]
正在建模一个类型类,那么对于traitFoobar[X]
有一个伴随对象Foobar
是很常见的,因为编译器会优先在object Foobar
中寻找示例定义。第二,关于各种进口:
只是一个包导入。令人困惑的是,因为你有一个类
Arithmetic.Arithmetic
和一个对象Arithmetic.Arithmetic
,这就把类和对象带到了作用域中。另一方面,这里这个
本质上说:* "在此代码块中,当您需要
+
或*
时,请询问ev: Arithmetic[T]
如何定义+
和*
"*。如何示例化
ev
取决于构造PE[T]
的示例化站点上的类型T
。,您实际上是在告诉编译器:* "亲爱的编译器,我很懒,在我导入的一些包中搜索
Arithmetic[UInt]
的示例"*.编译器将去看看哪里可以得到compilerGenerated_ev: Arithmetic[UInt]
,并自动将其作为隐式参数传递:然后
PE[T]
-initializer内部的主体将接管,从compilerGenerated_ev
导入*
和+
,并使用它们进行计算。这里,同样是更新的Scala 3语法的完整示例。它演示了编译器如何根据传递给
PE
-构造函数的内容插入两个不同的Arithmetic[Int]
和Arithmetic[Double]
示例。