You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala技术疑问:抽象类伴生对象合法性与ev参数指代

Scala类型类相关问题解答

代码场景

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._
  ...
}

技术疑问解答

1. 抽象类(如示例中的Arithmetic)是否可以拥有伴生对象?

可以。在Scala中,任何类(包括抽象类、特质、case类等)都可以拥有伴生对象。伴生对象与对应类必须同名且定义在同一源文件中,二者可互相访问私有成员。示例里的Arithmetic抽象类搭配同名伴生对象是完全合法的用法,这类伴生对象通常用来存放该类型类的具体实现实例(比如示例中的UIntArithmetic和SIntArithmetic)。

2. 当使用import Arithmetic._时,隐式参数ev指代的是伴生对象还是抽象类?

ev指代的是伴生对象中定义的、继承自Arithmetic[T]的隐式实例,也就是示例里的UIntArithmetic或SIntArithmetic,而非抽象类本身。

具体逻辑:

  • import Arithmetic._会将伴生对象Arithmetic内部的所有成员导入当前作用域,其中就包含UIntArithmetic和SIntArithmetic这两个隐式对象——它们是Arithmetic[UInt]和Arithmetic[SInt]的具体实现。
  • 当实例化PE[UInt]时,Scala会自动在当前作用域中寻找符合Arithmetic[UInt]类型的隐式值,也就是UIntArithmetic,并将其绑定到隐式参数ev上;实例化PE[SInt]时则会绑定SIntArithmetic。
  • 抽象类Arithmetic[T]只是一个类型模板,本身无法被实例化,ev的类型是Arithmetic[T],但实际传入的是它的子类实例(来自伴生对象的隐式对象)。

内容的提问来源于stack exchange,提问作者xlgforever

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 20:35:22