在Scala中将字符串作为泛型函数或函数调用进行求值

在Scala中将字符串作为泛型函数或函数调用进行求值,scala,generics,pattern-matching,Scala,Generics,Pattern Matching,我想编写一个通用函数functionChooser,它将根据字符串参数从几个选项中选择要使用的函数 这项工作: def a (arg: String) = arg + " with a" def b (arg: String) = arg + " with b" def c (arg: String) = arg + " with c" def functionChooser(func: String, additionalArg: String) = { val f = func m

我想编写一个通用函数
functionChooser
,它将根据字符串参数从几个选项中选择要使用的函数

这项工作:

def a (arg: String) = arg + " with a"
def b (arg: String) = arg + " with b"
def c (arg: String) = arg + " with c"

def functionChooser(func: String, additionalArg: String) = {
    val f = func match {
      case "a" => a _
      case "b" => b _
      case _ => c _
    }

    f(additionalArg)
}

scala> functionChooser("a", "foo")
res18: String = foo with a
我在使
functionChooser
泛型时遇到问题,例如,当函数
a
b
c
返回不同的案例类时:

case class A(s: String)
case class B(s: String)
case class C(s: String)

def a (arg: String) = A(arg)
def b (arg: String) = B(arg)
def c (arg: String) = C(arg)

//functionChooser def as before

scala> functionChooser("a", "foo")
res19: Product with Serializable = A(foo)
我不太明白我得到了什么,我知道调用
functionChooser(“a”,“foo”).s时出错(“
错误:值s不是可序列化的产品的成员”)

最后,我真正想要的是函数将返回这些案例类的列表,例如:

def a (arg: String) = List(A(arg))
def b (arg: String) = List(B(arg))
def c (arg: String) = List(C(arg))

因此
functionChooser
应该是
List[T]
的泛型,其中
T
是某个类。

您应该为所有三个函数返回上公共类型。对象(AnyRef)始终适合

def functionChooser(func: String, additionalArg: String) : AnyRef = {
在您的情况下,如果所有可能的返回值都是列表,您可以使用更具体的类型:

def functionChooser(func: String, additionalArg: String) : List[_] = {
当然,这将消除类型信息。任何方法都应该返回相同的类型,它不能是多态的。因此,您需要进一步使用
.asInstanceOf[T]
case来获取此信息

这是有道理的,因为实际类型在运行时是未知的。e、 g.调度器字符串可由用户输入。若它在编译时是已知的,那个么您可以只使用适当的方法而不引用描述性字符串


如果您想为所有可能的返回类型获得一些共同的行为,那么您应该为它们定义一个共同的特征,并为其放置共同的方法。

您应该为所有三个函数返回较高的共同类型。对象(AnyRef)始终适合

def functionChooser(func: String, additionalArg: String) : AnyRef = {
在您的情况下,如果所有可能的返回值都是列表,您可以使用更具体的类型:

def functionChooser(func: String, additionalArg: String) : List[_] = {
当然,这将消除类型信息。任何方法都应该返回相同的类型,它不能是多态的。因此,您需要进一步使用
.asInstanceOf[T]
case来获取此信息

这是有道理的,因为实际类型在运行时是未知的。e、 g.调度器字符串可由用户输入。若它在编译时是已知的,那个么您可以只使用适当的方法而不引用描述性字符串


如果您想获得所有可能返回类型的一些常见行为,那么您应该为它们定义一个共同特征,并为其放置共同的方法。

函数
functionChooser
将返回案例类
a
B
C
中最具体的通用超类型。由于案例类继承自
Product
Serializable
,因此常见的超类型是
Product with Serializable

如果要访问案例类字段
s
,则必须通过模式匹配强制转换结果,或者提供所有类
a
B
C
的公共基类,以便访问该字段

特征库{
def s:字符串
}
案例类别A(s:String)扩展了基础
案例类别B(s:String)扩展了基础
案例类C(s:String)扩展了基础
使用此类型定义,
functionChooser
的返回类型将是
Product,可与Base一起序列化
,因此,结果将允许您访问
s

如果您的函数
a
b
c
返回各自案例类的
列表
,则
functionChooser
的返回类型将是
列表[可与Base序列化的产品]

更新 如果无法更改类层次结构,则必须强制转换结果,或者可以在
functionChooser
中提取必要的信息,并将其包装为另一种类型,其中包含所需的所有数据的超集。例如

def functionChooser(func: String, additionalArg: String): String = {
    val f = func match {
      case "a" => (a _).s
      case "b" => (b _).s
      case _ => (c _).s
    }

    f(additionalArg)
}

注意:这里我只提取字段
s
,它是所有必需信息的超集。

函数
functionChooser
将返回案例类
A
B
C
的最具体的通用超类型。由于案例类继承自
Product
Serializable
,因此常见的超类型是
Product with Serializable

如果要访问案例类字段
s
,则必须通过模式匹配强制转换结果,或者提供所有类
a
B
C
的公共基类,以便访问该字段

特征库{
def s:字符串
}
案例类别A(s:String)扩展了基础
案例类别B(s:String)扩展了基础
案例类C(s:String)扩展了基础
使用此类型定义,
functionChooser
的返回类型将是
Product,可与Base一起序列化
,因此,结果将允许您访问
s

如果您的函数
a
b
c
返回各自案例类的
列表
,则
functionChooser
的返回类型将是
列表[可与Base序列化的产品]

更新 如果无法更改类层次结构,则必须强制转换结果,或者可以在
functionChooser
中提取必要的信息,并将其包装为另一种类型,其中包含所需的所有数据的超集。例如

def functionChooser(func: String, additionalArg: String): String = {
    val f = func match {
      case "a" => (a _).s
      case "b" => (b _).s
      case _ => (c _).s
    }

    f(additionalArg)
}

注意:这里我只提取字段
s
,它是所有必需信息的超集。

不做我想做的事,因为
functionChooser(“a”,“foo”)。s
我仍然会得到
错误:值s不是AnyRef
的成员。这是不可避免的,实际结果类型在编译器timentastic中是未知的,您的
.asInstanceOf
编辑完成了工作。谢谢对于
functionChooser(“a”,“foo”).s
I,不执行我想要的操作