scala 模式匹配_Scala模式匹配:新思维的案例?

scala 模式匹配

有新想法吗?

美国第16任总统。

亚伯拉罕·林肯曾经说过:“由于我们的案子是新的,因此我们必须重新考虑并采取行动”。

在软件工程中,事情可能不像内战和废除奴隶制那样剧烈,但是我们对“案例”有一个有趣的逻辑概念。

在Java中,case语句提供了一些有限的条件分支。

在Scala中,可以使用case / match构造构造一些非常复杂的模式匹配逻辑,这不仅带来了新的可能性,还带来了实现新可能性的新型思维。

让我们从经典的一年级计算机科学作业开始:一个斐波那契数列,该数列不是以0、1开头,而是以1、1开头。因此,该序列看起来像是:1、1、2、3、5、8 ,13,… 每个数字都是前两个数字的和

在Java中,我们可以这样做:

public int fibonacci(int i) {
    if (i < 0) 
        return 0;
    switch(i) {
        case 0:
            return 1;
        case 1:
            return 1;
        default:
            return fibonacci(i-1) + fibonacci(i - 2);
    }
}

一切顺利。 如果传入了0 ,它将算作系列中的第一个元素,因此应返回1注意:为聚会增加更多趣味性并使事情变得更有趣,我添加了一点逻辑,如果将负数传递给我们的fibonacci方法,则返回0

在Scala中,为了实现相同的行为,我们将执行以下操作:

def fibonacci(in: Int): Int = {
  in match {
    case n if n <= 0 => 0
    case 0 | 1 => 1
    case n => fibonacci(n - 1) + fibonacci(n- 2)
  }
}

关键点:

  • 递归方法fibonacci的返回类型是Int 。 递归方法必须明确指定返回类型(请参阅: Odersky –在Scala中编程 –第2章)。
  • 使用|可以测试一行上的多个值。 符号。 我这样做是为了在示例的第4行上为0和1返回1。
  • 不需要多个return语句。 在Java中,必须使用多个return语句或多个break语句。
  • 模式匹配是一个始终返回某些内容的表达式。
  • 在此示例中,我采用了一种防护措施来检查负数,如果它是负数,则返回零。
  • 在Scala中,还可以检查不同的类型。 也可以使用通配符_表示法。 我们并没有在斐波那契使用任何一个,只是为了说明这些功能……
    def multitypes(in: Any): String = in match {
      case i:Int => 'You are an int!'
      case 'Alex' => 'You must be Alex'
      case s:String => 'I don't know who you are but I know you are a String'
      case _ => 'I haven't a clue who you are'
    }

模式匹配可以与Scala Maps一起使用,以达到有用的效果。 假设我们有一张地图来捕捉我们认为应该在澳大利亚狮队系列赛的狮线后排位置上扮演谁的人。 地图的关键点将是后排中的位置,而相应的值将是我们认为应该在那儿玩的玩家。 为了代表橄榄球运动员,我们使用
案例类 。 现在,您现在是Java Heads,将case类视为以极其简洁的方式编写的不可变的POJO –它们也可以可变,但是现在认为不可变。

case class RugbyPlayer(name: String, country: String);
val robKearney = RugbyPlayer('Rob Kearney', 'Ireland');
val georgeNorth = RugbyPlayer('George North', 'Wales');
val brianODriscol = RugbyPlayer('Brian O'Driscol', 'Ireland');
val jonnySexton = RugbyPlayer('Jonny Sexton', 'Ireland');  
val benYoungs = RugbyPlayer('Ben Youngs', 'England');

// build a map
val lionsPlayers = Map('FullBack' -> robKearney, 'RightWing' -> georgeNorth, 
      'OutsideCentre' -> brianODriscol, 'Outhalf' -> jonnySexton, 'Scrumhalf' -> benYoungs);

// Note: Unlike Java HashMaps Scala Maps can return nulls. This achieved by returing
// an Option which can either be Some or None. 

// So, if we ask for something that exists in the Map like below
println(lionsPlayers.get('Outhalf'));  
// Outputs: Some(RugbyPlayer(Jonny Sexton,Ireland))

// If we ask for something that is not in the Map yet like below
println(lionsPlayers.get('InsideCentre'));
// Outputs: None

在此示例中,除了中心内线之外,我们每个位置都有球员-我们无法下定决心。 Scala Maps允许将空值存储为值。 现在在我们的情况下,我们实际上并没有在center中存储null。 因此,不是在中心内部返回null(就像我们使用Java HashMap那样会发生),而是返回None类型。

对于后行中的其他位置,我们具有匹配的值,并且返回Some类型,该类型环绕相应的RugbyPlayer。 (注意: SomeOptionOption扩展)。 我们可以编写一个函数,该函数 HashMap的返回值进行模式匹配 ,并向我们返回一些更加用户友好的东西。

def show(x: Option[RugbyPlayer]) = x match {
  case Some(rugbyPlayerExt) => rugbyPlayerExt.name  // If a rugby player is matched return its name
  case None => 'Not decided yet ?' // 
}
println(show(lionsPlayers.get('Outhalf')))  // outputs: Jonny Sexton
println(show(lionsPlayers.get('InsideCentre'))) // Outputs: Not decided yet

这个例子不仅说明了模式匹配,还提出了另一种概念,即提取 。 匹配时,将提取橄榄球播放器并将其分配给rugbyPlayerExt 。 然后,我们可以从rugbyPlayerExt获取橄榄球运动员名称的值。 实际上,我们还可以添加保护并围绕某些逻辑进行更改。 假设我们有偏见的记者(
斯蒂芬·琼斯(Stephen Jones ),他不希望任何爱尔兰球员入队。 他可以实施自己偏见的职能来检查爱尔兰球员

def biasedShow(x: Option[RugbyPlayer]) = x match {
  case Some(rugbyPlayerExt) if rugbyPlayerExt.country == 'Ireland' => 
     rugbyPlayerExt.name + ', don't pick him.'
  case Some(rugbyPlayerExt) => rugbyPlayerExt.name
  case None => 'Not decided yet ?'
}
println(biasedShow(lionsPlayers.get('Outhalf'))) // Outputs Jonny... don't pick him
println(biasedShow(lionsPlayers.get('Scrumhalf'))) // Outputs Ben Youngs

模式匹配集合

Scala还为集合提供了一些强大的模式匹配功能。 这是获取列表长度的简单示例。

def length[A](list : List[A]) : Int = list match {
  case _ :: tail => 1 + length(tail)
  case Nil => 0
}

假设我们想从一个元组解析参数……

def parseArgument(arg : String, value: Any) = (arg, value) match {
    case ('-l', lang) => setLanguage(lang)  
    case ('-o' | '--optim', n : Int) if ((0 < n) && (n <= 3)) => setOptimizationLevel(n)
    case ('-h' | '--help', null) => displayHelp()
    case bad => badArgument(bad)
  }

单参数功能

考虑一个从1到10的数字列表。filter方法采用单个参数函数,该函数返回
true false 。 单参数函数可以应用于列表中的每个元素,并且将为每个元素返回truefalse 。 返回true的元素将被过滤; 返回false的元素将被过滤出结果列表。

scala> val myList = List(1,2,3,4,5,6,7,8,9,10)
myList: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> myList.filter(x => x % 2 ==1)
res13: List[Int] = List(1, 3, 5, 7, 9)

现在现在现在,听听并记住这一点。 模式可以传递给采用单个参数函数的任何方法 。 与其传递总是返回true或false的单个参数函数,我们可以使用始终返回true或false的模式。

scala> myList.filter {
     |     case i: Int => i % 2 == 1   // odd number will return false
     |     case _ => false             // anything else will return false
     | }
res14: List[Int] = List(1, 3, 5, 7, 9)

以后用吗?

Scala将模式编译为PartialFunction 。 这意味着不仅可以将Scala模式表达式传递给其他函数,还可以将它们存储起来以备后用。

scala> val patternToUseLater = : PartialFunction[String, String] = {
     |   case 'Dublin' => 'Ireland'
     |   case _ => 'Unknown'
      }

这个例子说的是patternToUseLater是一个部分函数,​​它接受一个字符串并返回一个字符串。 默认情况下,返回函数中的最后一个状态,因为case表达式是部分函数,​​它将作为部分函数返回并分配给pattenrToUseLater ,后者当然可以在以后使用。

最后, 约翰尼·塞克斯顿Johnny Sexton)是一位出色的橄榄球运动员,听到他要离开伦斯特(Leinster)感到可耻。 显然,由于Sexton忙碌的日程安排,我们不能确定Johnny是否正在阅读此博客,但是如果Johnny是他,Johnny很抱歉看到您离开,我们祝您一切顺利,并希望您有一天能回到Blue Jersey。

参考: Scala模式匹配:新思维的案例? 从我们的JCG合作伙伴 Alex Staveley在都柏林的技术博客博客中获得。

翻译自: https://www.javacodegeeks.com/2013/01/scala-pattern-matching-a-case-for-new-thinking.html

scala 模式匹配

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值