Scala - 在模式匹配中指定匹配项

8

I have the following code:

class Animal(hair: Option[Hair])

class Cat(var hair: Option[Hair]) extends Animal(hair)
class Dog(var hair: Option[Hair]) extends Animal(hair)
class Sheep(var hair: Option[Hair]) extends Animal(hair)

//then somewhere else:

def what(animal: Animal) {

  animal match {
    case Cat(hair) => println("processing cat, hair=" + hair)
    case Dog(hair) => println("processing dog, hair=" + hair)
    case Sheep(hair) => {
      println("processing sheep, cutting hair...")
      hair = None
    }
  }
}

问题如下:
1)当模式匹配成功时,如何访问Sheep的毛并更改它?它抱怨对val的重新赋值,于是我在构造函数中放置了var,但仍然……
2)我能想到的另一种方法是将整个匹配的值分配给一个变量,有没有办法将由某个case类构造函数模式匹配的值绑定到一个变量上?
(我知道我可能可以在像s:Sheep这样的东西上进行模式匹配,然后调用s.changeHairTo(None),但那是最不理想的方式)。
2个回答

25

你可以在你的版本中使用@将整个模式绑定到变量上。

class Animal(hair: Option[Hair])
case class Cat(var hair: Option[Hair]) extends Animal(hair)
case class Dog(var hair: Option[Hair]) extends Animal(hair)
case class Sheep(var hair: Option[Hair]) extends Animal(hair)

def what(animal: Animal) {
  animal match {
    case Cat(hair) => println("processing cat, hair=" + hair)
    case Dog(hair) => println("processing dog, hair=" + hair)
    case s @ Sheep(hair) => {
      println("processing sheep, cutting hair...")
      //cut(hair)
      s.hair = None
    }
  }
}

但您不必使用var。这是您的片段更具功能性的版本。 what 在这里只返回经过修剪的Sheep和没有HairNone

trait Animal
case class Cat(hair: Option[Hair]) extends Animal
case class Dog(hair: Option[Hair]) extends Animal
case class Sheep(hair: Option[Hair]) extends Animal

def what(animal: Animal): Animal =
  animal match {
    case Cat(hair) => {
      println("processing cat, hair=" + hair)
      animal
    }
    case Dog(hair) => {
      println("processing dog, hair=" + hair)
      animal
    }
    case Sheep(hair) => {
      println("processing sheep, cutting hair...")
      //cut(hair)
      Sheep(None)
    }
  }
}

4

这种方式是不可行的,因为在模式匹配中,“hair”变量只是从Sheep对象中提取出来的,所以它不是Sheep的字段,而是case块上下文中的一个变量。你可以像这样做:

class Hair

trait Animal {
  var hair: Option[Hair]
}
case class Cat(var hair: Option[Hair]) extends Animal
case class Dog(var hair: Option[Hair]) extends Animal
case class Sheep(var hair: Option[Hair]) extends Animal

//then somewhere else:

def what(animal: Animal) {

  animal match {
    case Cat(hair) => println("processing cat, hair=" + hair)
    case Dog(hair) => println("processing dog, hair=" + hair)
    case Sheep(hair) => {
      println("processing sheep, cutting hair...")
      animal.hair = None
    }
  }
}

只需告诉Animal它有一个可变的字段hair,您就可以设置它,而无需将其强制转换为正确的类型。

尽管这样可以工作,但我更喜欢4e6的第一个块作为更好的替代方案。你知道在case语句中你正在处理一个“Sheep”,因此没有必要让所有的“Animal”都需要处理可变的毛发。一般来说,最小化可变性是一件好事,而另一种方法也让猫和狗也具有不可变的头发。 - Andrzej Doyle
我完全同意你的两点观点。但是他的Cat和Dog类已经有可变的hair字段了;-) - drexin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接