2016-02-10 33 views
1

我最近开始学习scala和广告,尝试熟悉一个简单的演示程序。斯卡拉嵌套可选项链接对象

我想检查一个单元格是否具有所有邻居。在Java中,这可以通过完成:

public boolean hasFullNeighbourhood() { 
    if (top != null && bottom != null && left != null && right != null && 
      top.getLeft() != null && top.getRight() 
      != null && bottom.getLeft() != null 
      && bottom.getRight() != null) 
     return true; 
    else 
     return false; 
} 

小区被定义为:

class Cell(
      val x: Int, 
      val y: Int, 
      val left: Option[Cell], 
      val right: Option[Cell], 
      val top: Option[Cell], 
      val bottom: Option[Cell], 
      var isPainted: Boolean) 

我如何定义Scala中的一个完整的邻里关系? 我开始喜欢:

def hasFullNeighbourhood(r:Int): Boolean={ 
     if(r ==0) 
      return true 
     if (List(top, bottom, left, right).forall(_.isDefined)) 
      return true 
     else 
      return false 
    } 

但如何访问其余(x.top, x.bottom, x.left, x.right),并检查是否这些不是空/可选不清我。

我认为像top.foreach()将是可能的 - 但如果添加到选项列表中,它不会失败,如果这返回none

编辑

我重新定义了我的课作为一个案例类:

case class Cell(
      val x: Int, 
      val y: Int, 
      val left: Option[Cell], 
      val right: Option[Cell], 
      val top: Option[Cell], 
      val bottom: Option[Cell], 
      var isPainted: Boolean) 

这是否意味着

def isMiddleCell()={ 
    if(List(top, bottom, left, right).forall(_.isDefined)) 
     true 
    else 
     false 
    } 

可以改写为:

def isMiddleCell(c: Cell) = c match { 
    case Cell(_, _, Some(top), Some(bottom), Some(left), Some(right), _) => true 
    case _ => false 
    } 

仍然似乎有点奇怪,我宁愿要检查一个给定的细胞,如果这个人是一个中间电池的不指定Cell.isMiddleCell(givenCell)而是givenCell.isMiddleCell()

但是实施

def hasFullNeughbourhood(radius:Int)正确就不会我需要一些更多的语句我不仅想检查直接的邻居。对我而言,目前还不清楚如何访问这些内容。在Java中,我会使用x.getLeft()和递归x.getLeft().hasFullNeighbourhood(r - 1)

def hasFullNeighbourhood(c: Cell) = c match { 
    case Cell(_, _, Some(top), Some(bottom), Some(left), Some(right), _) => true 
    case _ => false 
    } 

EDIT2

做我理解正确的是isMiddleCell应该被实现为:

def isMiddleCell() = { 
    this match { 
     case Cell(_, _, Some(top), Some(bottom), Some(left), Some(right), _) => true 
     case _ => false 
    } 

回答

1

通常有好的方法来执行对Scala中的一个容器的内容的操作:映射或通过模式匹配进行分解。如果您不习惯功能性编程,则在选项的情况下,模式匹配更直观。

为了使模式匹配更容易,您应该将您的单元类定义为一个案例类。这给你模式匹配,而不必自己实现任何东西,并会使下一个示例更好。案例类对于简单的数据模型类来说总是一个好主意。

def hasFullNeighbourhood(c: Cell) = c match { 
    case Cell(_,_,Some(top),Some(bottom),Some(left),Some(right),_) => true 
    case _ => false 

我留在变量名顶部底部等等,因为你可以使用这些值来处理这些值。但是因为你不需要这个方法,所以我也可以写成_。如果您还不知道模式匹配,请阅读它。没有它的Scala并不好玩。

另一种方式是使用地图。如果你想要做的东西,一些计算中的“容器”,并把它放回同一种容器的这仅仅是有趣:

val possiblyANumber1 = Some(5) 
val possiblyANumber2 = Some(5) 
val possiblyANumber3 = possiblyANumber1.flatMap(x => possiblyANumber2.map(y => x + y)) 

在这个例子中,这允许你做对两个数字相加不知道它们是否真的存在。

+0

谢谢你的解释。请你可以解释一下'_'有多使用了,而不是'x,y,isPainted'?请参阅编辑。我仍然需要一些解释:) –

+0

是的,基本上你可以嵌套这些模式来描述你想要的结构。当你想要访问你在其中放置一个变量名称的内容时,如果你不关心你刚刚放置一个_的内容。变量名称可以是任意名称,它们不必与参数的名称或类似的名称相对应。 – dth

+0

非常感谢。 –