通过scala中的反射检查两种类型是否等价

Check if two types are equivalent through reflection in scala

我有一些代码:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

trait LogicUnit

trait Ezib extends LogicUnit
trait Zieb extends LogicUnit

object LogicUnit {

    @inline 
    def combine[A <: LogicUnit, B <: LogicUnit](arg1: A, arg2: B): Future[LogicUnit] = {

        if (arg1.isInstanceOf[Ezib] && arg2.isInstanceOf[Ezib]) return Future(new Ezib {})
        else if (arg1.isInstanceOf[Zieb] && arg2.isInstanceOf[Zieb]) return Future(new Zieb {})

        else if (arg1.isInstanceOf[Ezib] && arg2.isInstanceOf[Zieb]) return Future(new Zieb {})
        else return Future(new Ezib {})
    }
}

由于这段代码会 运行 很多,因此我正在尝试对其进行大量优化,因此,我正在尝试合并 combine 函数的前两行。为此,我认为代码看起来像这样:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

trait LogicUnit

trait Ezib extends LogicUnit
trait Zieb extends LogicUnit

object LogicUnit {

    @inline 
    def combine[A <: LogicUnit, B <: LogicUnit](arg1: A, arg2: B): Future[LogicUnit] = {

        if (arg1.isInstanceOf[typeOf(arg2)]) return Future(arg1)

        else if (arg1.isInstanceOf[Ezib] && arg2.isInstanceOf[Zieb]) return Future(new Zieb {})
        else return Future(new Ezib {})
    }

}

有什么方法可以让代码只检查两种类型是否相同,这样我就不必匹配所有情况?

这里有很多问题:

这些测试不太可能对性能产生任何影响,因为创建 运行 一个 Future 是一个复杂得多的操作,并且会占用大量时间。

类型参数是不必要的,因为值总是被视为 LogicUnit,所以签名可以是:

def combine(arg1: LogicUnit, arg2: LogicUnit): Future[LogicUnit]

最好使用 match 而不是 isInstanceOf,因为编译器会知道参数的类型。

第一个版本不依赖于arg1的类型所以不用测试:

def combine(arg1: LogicUnit, arg2: LogicUnit): Future[LogicUnit] =
  arg2 match {
    case _: Ezib => Future(new Ezib {})
    case _: Zieb => Future(new Zieb {})
  }

如果您确实需要测试两个参数,请嵌套测试以免重复第一个测试:

def combine(arg1: LogicUnit, arg2: LogicUnit): Future[LogicUnit] =
  arg1 match {
    case a1: Ezib =>
      arg2 match {
        case a2: Ezib => Future(???)
        case a2: Zieb => Future(???)
      }
    case a1: Zieb =>
      arg2 match {
        case a2: Ezib => Future(???)
        case a2: Zieb => Future(???)
      }
  }

这个公式清晰易读,它允许每个分支使用 a1a2 的值,编译器知道这些值是已匹配的特定类型。

也可能是使用 combine 的多态版本会提高性能:

def combine(arg1: Ezib, arg2: Ezib): Future[LogicUnit] = ???
def combine(arg1: Ezib, arg2: Zieb): Future[LogicUnit] = ???
def combine(arg1: Zieb, arg2: Ezib): Future[LogicUnit] = ???
def combine(arg1: Zieb, arg2: Zieb): Future[LogicUnit] = ???

def combine(arg1: LogicUnit, arg2: LogicUnit): Future[LogicUnit] =
  arg1 match {
    case a1: Ezib =>
      arg2 match {
        case a2: Ezib => combine(a1, a2)
        case a2: Zieb => combine(a1, a2)
      }
    case a1: Zieb =>
      arg2 match {
        case a2: Ezib => combine(a1, a2)
        case a2: Zieb => combine(a1, a2)
      }
  }

如果在调用点已知具体类型,则编译器可以直接调用适当的方法,而不必匹配类型。