2

我定义了以下类 PositionSpace,它具有嵌套类 Position 和 SubPositionSpace。SubPositionSpace 本身既是 Position 又是 PositionSpace(因此它是一个也定义了自己的位置的位置)。我已经定义了一个包装类 SubPosition,以便任何类型为 x.SubPositionSpace#Position 的对象(对于任何作为 PositionSpace 的对象 x)都可以用作类型为 x.Position 的对象。但是,我想让这种转换隐含,这就是我卡住的地方。从逻辑上讲,这应该是可能的。但是,我不知道在哪里或如何定义转换以便编译器找到它,这让我很头疼。

下面是我的代码。请注意,我已在底部添加了测试用例。

class PositionSpace { positionSpace =>

  //snip

  trait Position extends Ordered[Position] {
    //snip
  }

  class SubPositionSpace() extends PositionSpace with Position { subPositionSpace =>

    //snip

    //wrapper class to treat a x.SubPositionSpace#Position as a x.Position for some x : PositionSpace
    //want to make this conversion implicit!!!
    class SubPosition(private val subPositionIndex : subPositionSpace.Position) extends positionSpace.Position {
      //snip
    }
  }

  def append() = new Position{
    //snip
  }

  def appendSubSpace() = new SubPositionSpace()
}

object TestCases {
  val positionSpace = new PositionSpace()
  val subSpace = positionSpace.appendSubSpace()
  val subSpacePosition = subSpace.append()
  //Does not compile, needs an implicit conversion:
  val subSpacePositionAsPosition : positionSpace.Position = subSpacePosition
  val subSubSpace = subSpace.appendSubSpace()
  //Does not compile, needs an implicit conversion:
  val subSubSpacePositionAsPosition : positionSpace.Position = subSubSpace
}

到目前为止我遇到的障碍

路径相关类型

部分问题似乎是这种转换涉及依赖于路径的类型,其中输入类型和输出类型使用相同的路径。但是,没有语法可以编写带有类型签名的方法x.Position => y.Position where y : PositionSpace and x : y.SubPositionSpace. 通过添加附加参数以传递路径(如下所示)很容易解决问题,但是您不能向隐式转换方法添加附加参数(如果你希望它们被这样使用)。

//Too many arguments, won't be used by compiler for implicit conversions
implicit def promotePosition(y : PositionSpace, x : y.PositionSpace, x.Position) : y.Position = ...
4

2 回答 2

1

这是我想出并开始工作的部分答案。基本上,您创建了一个空特征 SubPositionSpacePosition,它将应用于所有 2 级位置。然后,您可以为定义隐式转换的 SubPositionSpacePosition 定义一个伴随对象。您只能定义 2 级职位到 1 级职位的转换。除此之外的任何事情,您都会遇到我在问题中概述的障碍。

import scala.language.implicitConversions

class PositionSpace { positionSpace =>

  trait Position extends Ordered[Position] {

  }

  trait SubPositionSpace extends PositionSpace with Position { subPositionSpace =>
    trait SubPositionSpacePosition extends subPositionSpace.Position {
    }

    def append() = new Position with SubPositionSpacePosition { }

    def appendSubSpace() = new SubPositionSpace with SubPositionSpacePosition { }

    class SubPosition(private val subPositionIndex : subPositionSpace.Position) extends positionSpace.Position {
    }

    object SubPositionSpacePosition {
      implicit def promoteSubPositionSpacePosition(subPositionSpacePosition : SubPositionSpacePosition) : positionSpace.Position =
        new SubPosition(subPositionSpacePosition)
    }
  }

  def append() = new Position { }

  def appendSubSpace() = new SubPositionSpace { }
}

object TestCases {
  val positionSpace = new PositionSpace()
  val subSpace = positionSpace.appendSubSpace()
  val subSpacePosition = subSpace.append()
  val subSpacePositionAsPosition : positionSpace.Position = subSpacePosition
  val subSubSpace = subSpace.appendSubSpace()
  val subSubSpacePosition = subSubSpace.append()
  //this still fails to build!!!
  val subSubSpacePositionAsPosition : positionSpace.Position = subSubSpacePosition
}
于 2013-11-24T09:53:15.843 回答
0

我认为您不希望在这里进行隐式转换 - 只需为类型系统提供跟踪依赖路径的类型所需的信息会更加简洁。一种方法是抽象出将类型联系在一起的骨架:

trait PSpace { pSpace =>
  type P
  type Sub <: P with PSpace {
    type P = pSpace.P
    type Sub = pSpace.Sub
  }

  def append(): P
  def appendSubSpace(): Sub
}

您也可以使用类型参数,但我猜类型成员会更适合您的用例。然后你提供你的实现:

class PositionSpace { positionSpace =>
  type P = Position
  type Sub = SubPositionSpace

  trait Position

  class SubPositionSpace() extends PSpace with Position {
    type P = positionSpace.P
    type Sub = positionSpace.Sub

    class SubPosition(private val subPositionIndex: P) extends P

    def append() = new Position {}
    def appendSubSpace() = new SubPositionSpace()
  }

  def append() = new Position {}
  def appendSubSpace() = new SubPositionSpace()
}

现在您的测试代码的所有行都可以正常编译。

于 2013-11-23T15:22:55.133 回答