Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Scala中获取结构联合类型?_Scala_Types_Polymorphism_Duck Typing - Fatal编程技术网

如何在Scala中获取结构联合类型?

如何在Scala中获取结构联合类型?,scala,types,polymorphism,duck-typing,Scala,Types,Polymorphism,Duck Typing,我不确定“结构联合类型”是否是正确的术语,但我试图在Scala中获得以下duck类型行为 假设我有一些容器类container,其中包含获取A和B类型对象的方法: 类容器{ def getA:A def getB:B } A和B都有一个commontinfield属性,但它们也有一些非共享方法: A类{ val commonIntField:Int def getAStringField1:字符串 def getAStringField2:字符串 } B类{ val commonIntFiel

我不确定“结构联合类型”是否是正确的术语,但我试图在Scala中获得以下duck类型行为

假设我有一些容器类
container
,其中包含获取
A
B
类型对象的方法:

类容器{
def getA:A
def getB:B
}
A
B
都有一个
commontinfield
属性,但它们也有一些非共享方法:

A类{
val commonIntField:Int
def getAStringField1:字符串
def getAStringField2:字符串
}
B类{
val commonIntField:Int
def getBStringField:字符串
}
现在假设我想定义以下三个函数,它们看起来非常相似:

def f1(c:容器)={ val a=c.getA (0到a.commonIntField)foreach{println(a.getAStringField1)} } def f2(c:容器)={ val a=c.getA (0到a.commonIntField)foreach{println(a.getAStringField2)} } def f2(c:容器)={ valb=c.getB (0到b.commonIntField)foreach{println(a.getBStringField)} } 我要找的是某种干燥方法,例如:

def(getAOrB,getStringField)(c:容器)={
val aOrB=c.getAOrB
(0到aOrB.commonIntField)foreach{println(aOrB.getStringField)}
}
val f1=f(u.getA,u.getAStringField1)
val f2=f(u.getA,u.getAStringField2)
val f3=f(u.getB,u.getBStringField)

我的问题:我可以使用什么类型参数来编译
f
?(这里假设我不能更改
容器
A
B
的定义,尽管如果需要,我当然可以定义辅助类型。)

您应该向
f
添加一个类型参数并对其进行约束

因此,我们首先添加参数并对其进行相应的重构:

def f[T](tGetter: Container => T, getStringField: T => String)(c: Container) = {
  val t: T = tGetter(c)
  val intField =  getIntField(t)
  (0 to intField) foreach { println(stringGetter(t)) }
}
还有一个问题——我们如何定义从容器中获取T的方式? 更简单的方法-只需添加
tGetter:Container=>T
作为第一个参数。这是一个附加参数,但很简单,它将帮助您自动派生类型参数的类型

def f[T](tGetter: Container => T, getStringField: T => String)(c: Container) = {
  val t: T = tGetter(c)
  val intField: Int = ??? // getIntField(t)
  (0 to intField).foreach { _ => println(getStringField(t)) }
}
// val f1 = f(_.getA, _.getAStringField1) // the old one
val f1 = f[A](_.getA, _.getAStringField1)(_)
// val f2 = f(_.getA, _.getAStringField2)
val f2 = f[A](_.getA, _.getAStringField2)(_)
// val f3 = f(_.getB, _.getBStringField)
val f3 = f[B](_.getB, _.getBStringField)(_)
但是有一个问题-我们如何得到int字段? 我们有几种方法

1.结构分型 您只需像这样表达所需的结构类型
{def commonIntField:Int}
,并为T编写类型上限:

def f[T <: { def commonIntField: Int }](tGetter: Container => T, getStringField: T => String)(c: Container) = {
然后,为希望在此类功能中支持的每个类创建该类型类的实例

object HaveIntField {
  implicit val haveIntField_A_Instance: HaveIntField[A] = new HaveIntField[A] { 
    def getIntField(a: A): Int = a.commonIntField
  }
  implicit val haveIntField_A_Instance: HaveIntField[A] = new HaveIntField[A] { 
      def getIntField(a: A): Int = a.commonIntField
  }
}
最后,在T上添加上下文绑定

def f[T: HaveIntField](tGetter: Container => T, getStringField: T => String)(c: Container) = {  
  val t: T = tGetter(c)
  val intField =  implicitly[HaveIntField[T]].getIntField(t)
  0 to intField) foreach { println(stringGetter(t)) }
}
在Scala 2中,这看起来有点令人讨厌和难以忍受,但它是FP/Haskell提出的一个很酷的概念。在即将到来的Scala 3中,它将非常平滑

object HaveIntField {
  implicit val haveIntField_A_Instance: HaveIntField[A] = new HaveIntField[A] { 
    def getIntField(a: A): Int = a.commonIntField
  }
  implicit val haveIntField_A_Instance: HaveIntField[A] = new HaveIntField[A] { 
      def getIntField(a: A): Int = a.commonIntField
  }
}
def f[T: HaveIntField](tGetter: Container => T, getStringField: T => String)(c: Container) = {  
  val t: T = tGetter(c)
  val intField =  implicitly[HaveIntField[T]].getIntField(t)
  0 to intField) foreach { println(stringGetter(t)) }
}