Arithmetic.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._
...
}
我的問題是:
- 抽象類可以有伴生物件嗎?(比如Arithmetic)
- 我知道有一些隱式轉換。讓我感到困惑的是,當我使用時
import Arithmetic._,ev指的是什么?伴隨物件還是抽象類?
uj5u.com熱心網友回復:
首先,關于我們是否可以定義一個物件Arithmetic,如果已經有一個特征/類Arithmetic:是的。有兩種獨立的名稱:型別名稱和值名稱。抽象類宣告和特征宣告,例如
abstract class Arithmetic[A] // or
trait Arithmetic[A]
引入一個名為name的命名型別Arithmetic。伴隨物件宣告
object Arithmetic
引入一個值名稱 Arithmetic。型別名稱和值名稱存在于不同的領域,不會發生沖突。
如果正在對型別類進行建模,那么Foobar為特征配備伴生物件Foobar[X]是很常見的,因為編譯器將優先在.Foobar[X]object Foobar
二、關于各種進口:
import Arithmetic._
只是一個包匯入。令人困惑的是,因為您有一個 classArithmetic.Arithmetic和 object Arithmetic.Arithmetic,所以這會將 class 和 object 帶入范圍。
另一方面,這里
import ev._
本質上說:“在這段代碼中,當你需要 or時*,去詢問和是ev: Arithmetic[T]如何定義的” *。
如何ev實體化取決于構造T實體化站點的型別。PE[T]如果你正在建造
val myUInt: UInt = ...
new PE[UInt](myUInt)
,你實際上是在告訴編譯器:“親愛的編譯器,我很懶,去搜索Arithmetic[UInt]我匯入的一些包中的實體”。編譯器會去看看它在哪里可以得到一個compilerGenerated_ev: Arithmetic[UInt],并自動將它作為隱式引數傳遞:
val myUInt: UInt = ...
// ??: found it in `Arithmetic.UIntArithmetic`
val compilerGenerated_ev: Arithmetic[UInt] = Arithmetic.UIntArithmetic
new PE[UInt](myUInt /* ???♂? */)(compilerGenerated_ev /* ?? */)
然后 -initializer 內部的PE[T]主體將接管,從 中匯入*and ,并用它進行計算。 compilerGenerated_ev
此處再次提供了更新后的 Scala 3 語法中的完整示例。它演示了編譯器如何根據傳遞給-constructor的內容插入兩個不同的Arithmetic[Int]and實體。Arithmetic[Double]PE
// This is just a package (it's very confusing that
// in your example, the package is also named `Arithmetic`
package arithmetic {
// This defines what it means that "we can do Arithmetic on carrier set `A`"
trait Arithmetic[A]:
// Doing arithmetic on `A` means that we can add and multiply `A`s
extension (a: A)
infix def *(other: A): A
infix def (other: A): A
// The companion object of the typeclass `Arithmetic` is one of the first
// places where the compiler will search for instances of `Arithmetic[A]`
object Arithmetic {
// We can do arithmetic with integers
given Arithmetic[Int] with
extension (i: Int)
infix def *(other: Int) = i * other
infix def (other: Int) = i other
// We can do arithmetic with Doubles
given Arithmetic[Double] with
extension (d: Double)
infix def *(other: Double) = d * other
infix def (other: Double) = d other
}
}
// This import says:
// "bring `trait Arithmetic[T]` and
// companion `object Arithmetic` into
// scope
import arithmetic._
// This class has the superpower of computing `x * x x`
// for `x: T`, provided that we can do arithmetic on `T`.
class PE[T](x: T)(using ev: Arithmetic[T]) {
// This import says:
// "In the following, when looking for definitions for ` `
// and `*`, look inside of the `ev`
import ev.*
def foobar: T = x * x x
}
@main def example(): Unit = {
println(PE(42).foobar) // 1806: Int
println(PE(0.001).foobar) // 0.001001: Double
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/535798.html
