【问题标题】:Is there some way in scala that I can return a type?scala中有什么方法可以返回一个类型吗?
【发布时间】:2021-01-08 03:43:12
【问题描述】:

我有很多课程,例如DataFrameFlowTextFlowRDDFlow。它们都派生自基类Flow

现在我想编写一个函数judgeFlow,它可以从path: String 中读取并返回代表确切Flow 类型的东西,我可以从中创建相应的实例。整个代码如下所示

def judgeFlow(path:String) = /*1*/ {
  Flow.getStoreType(path) match {
    case StoreType.tdw =>
      DataFrameFlow
    case StoreType.hdfs =>
      TextFlow
  }
}

def createFlow(typeInfo:/*2*/) = /*3*/{
  new typeInfo()
}

但是,我不知道如何在位置 1、2 和 3 中写。

编辑

在这里知道如何构造它们是不够的,因为我还想要以下内容:

  1. 通过typeInfo进行模式匹配
  2. 一些方法asInstanceOf

编辑 2

Flow的定义

abstract class Flow(var outputName: String) extends Serializable{
  def this() = this("")
...
}

DataFrameFlow的定义

class DataFrameFlow(d: DataFrame, path: String) extends Flow {
  var data: DataFrame = d

  def this(data: DataFrame) = this(data, "")
  def this(path: String) = this(null, path)
  def this() = this(null, "")
...
}

【问题讨论】:

  • 如果您打算对事物做的只是构造它,您可以考虑返回一个 0 元函数来进行构造。
  • @SilvioMayolo 做建筑还不够,我还需要 asInstanceOf 的东西
  • 您的示例不具有代表性,您的课程怎么样(Flow,DataFrameFlow 等)?例如case class Flow(id: Int, ....),也可以提供一些数据示例。
  • @Chema 他们的定义太大了,我认为他们无关紧要。 Flow 是一个抽象类,DataFrameFlow 继承了它。我正在尝试提供更详细的代码,但这需要一些时间
  • 嗨@calvin,如果它们是案例类,您可以进行模式匹配来构建您的对象。

标签: scala reflection types pattern-matching scala-reflect


【解决方案1】:

模式匹配不能从不同的情况下返回不同的类型。模式匹配返回的类型是case返回类型的最小上限。

当有人想要返回不同的类型时,很可能他/她想要一个类型类。

sealed abstract class Flow
class DataFrameFlow extends Flow
class TextFlow extends Flow
class RDDFlow extends Flow

trait JudgeFlow[In] {
  type Out <: Flow
  def judgeFlow(in: In): Out
}
object JudgeFlow {
  implicit val `case1`: JudgeFlow[???] { type Out = DataFrameFlow } = ???
  implicit val `case2`: JudgeFlow[???] { type Out = TextFlow } = ???
  implicit val `case3`: JudgeFlow[???] { type Out = RDDFlow } = ???
}
  
def judgeFlow[In](in: In)(implicit jf: JudgeFlow[In]): jf.Out = jf.judgeFlow(in)

但问题是类型是在编译时解析的。您似乎想根据字符串的值选择一个案例,即在运行时。所以你不能在编译时返回比Flow更具体的类型。

flatMap with Shapeless yield FlatMapper not found


很难完全猜出您的用例。

但是使用Scala reflection你可以试试

import scala.reflect.runtime.universe._
import scala.reflect.runtime.currentMirror

def judgeFlow(path:String): Type = {
  Flow.getStoreType(path) match {
    case StoreType.tdw =>
      typeOf[DataFrameFlow]
    case StoreType.hdfs =>
      typeOf[TextFlow]
  }
}

def createFlow(typeInfo: Type): Flow = {
  val constructorSymbol = typeInfo.decl(termNames.CONSTRUCTOR).asMethod
  val classSymbol = typeInfo.typeSymbol.asClass
  val classMirror = currentMirror.reflectClass(classSymbol)
  val constructorMirror = classMirror.reflectConstructor(constructorSymbol)
  constructorMirror().asInstanceOf[Flow]
}

【讨论】:

  • 您好 Dmytro,我认为您的意思是我不能在编译时执行此操作,但是,如果只是在运行时执行此操作呢?我知道有一些反射策略可以让我获得声明的构造函数,但是它并不能完全解决我的问题,因为我仍然需要一些可以在运行时“操作”类型的东西,例如,类型 A 派生自类型/type 参数/trait B,或者是A 完全等于类型B。我知道有诸如typeOf/getClass/ClassTag之类的东西,我最终可以得到它,但我真的迷路了,我想知道是否有一些包裹或其他东西
  • @calvin ClassTag/TypeTag 将保留运行时的编译时信息。 “但是,如果只是在运行时执行此操作会怎样?” 好的,但是您必须在编译时返回一些类型。所以/*1*/ 将只是Flow(不是特定的子类型)。没事吧?
  • 是的,这个函数现在可以返回任何东西,甚至像com.xxx.xxx.DataFrameFlow这样的字符串,我可以用java.lang.Class.getDeclaredConstructor做实例化,用一些java.lang.reflect.Method做调用,和做一些其他方法的类型比较.但是,这些方式比较混乱,有时还需要额外的操作,比如处理伴生对象,所以想知道这里有没有一些简单/整洁的解决方案,可能是C++中的&lt;type_traits&gt;之类的函数?
  • @calvin 我重读了你的问题,也许我首先误解了它。您不希望 judgeFlow 返回具有特定子类型的 Flow 实例,而是希望它返回有关实例的一些类型/类信息。您应该添加一些使用judgeFlowcreateFlow 的示例(正如您想象的那样)。输入和期望的输出。当前的行为,它有什么问题,以及你想如何解决它。 (是的,类型信息可以是字符串或标签。)
  • @calvin 我对 C++ 中的类型特征不太熟悉。要么你有足够的信息在编译时进行操作,然后你可以使用宏、无形、编译时反射、隐式/类型类等来完成。或者你只有在运行时才有必要的信息(这似乎是因为你从运行时字符串 path 开始,或者它是编译时字符串文字?)然后你必须使用运行时反射(Java 反射:ClassMethod 等或 Scala 反射:Symbol、@ 987654349@、Mirror 等)。如果您想要更好的答案...
猜你喜欢
  • 2016-05-13
  • 1970-01-01
  • 1970-01-01
  • 2020-06-20
  • 1970-01-01
  • 2011-09-27
  • 1970-01-01
  • 2017-08-01
  • 2012-11-28
相关资源
最近更新 更多