Scala编程基础:表达式、函数、模式匹配与集合操作

这篇具有很好参考价值的文章主要介绍了Scala编程基础:表达式、函数、模式匹配与集合操作。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

讲解了Scala的集合操作,如筛选、转换、集合运算等,并介绍了如何在Scala中读取数据源和进行隐式转换。

Scala的设计理念是,特定领域的应用程序开发往往需要特定于该领域的语言扩展。

Scala提供了许多独特的语言机制,可以以库的形式轻易无缝添加新的语言结构。

表达式

在Scala中,一切皆为表达式。Scala非常推崇表达式语法,因为表达式语法对函数式编程非常友好。对于开发者来说,表达式语法使得代码非常简洁易读。

例如,我们在定义方法时,会和声明变量一样,使用等号(=)连接。等号左侧是函数名、参数列表和返回值类型(可以省略),而等号右边则是一个由大括号({})包裹的多行表达式。

在Scala中,每个表达式都会有返回值。在Java中,我们使用void来声明无返回值的方法,但在Scala里,这种情况也会有返回值,会返回一个Unit,这是一个特定的值,表示忽略方法的返回值。

方法与函数

对于Scala初学者来说,方法和函数的概念可能会有些模糊,在使用中可能会搞不清楚到底该使用方法还是函数。那么,如何区分呢?关键在于看这个函数是否在类中定义。如果在类中定义,那么它就是方法,因此Scala的方法是类的一部分。而Scala中的函数则是一个完整的对象,可以赋给一个变量。不过,在Scala中,方法和函数是可以相互转化的。下面我们重点介绍如何把方法转为函数。

方法转函数

上文中提到,任何方法都是在声明一个表达式,所以将方法转为函数就非常简单了,相当于是把方法指向的表达式,又重新赋给了一个函数变量,这就是显式转化。还有另外一种写法,是通过偏应用函数的方式,将方法转化为一个新的函数,称作隐式转化。

1)隐式转化

val f2 = f1 _

2)显式转化

val f2: (Int) => Int = f1

模式匹配

模式匹配是检查某个值是否匹配某一个模式的机制。它是Java中的switch语句的升级版,同样可以用于替代一系列的 if/else 语句。以下介绍几种常用的模式匹配:常量模式、变量模式、通配符模式。

常量模式

常量模式匹配,就是在模式匹配中匹配常量。

object ConstantPattern{
  def main(args:Array[String]) :Unit = {
    //模式匹配结果作为函数返回值
    def patternShow(x : Any) = x match {
        //常量模式
      case 5 => "五"
      case true => "真"
      case "test" => "字符串"
      case null => "null值"
      case Nil => "空列表"
        //变量模式
        case x => "变量"
        //通配符模式
      case _ => "通配符"
    }
  }
}

变量模式和通配符模式,都可以匹配任意值,他们之间的区别是,变量模式匹配成功后,该变量中会存储匹配成功的值,在后续的代码中还可以引用,而通配符模式匹配成功后,不能再引用匹配到的值。另外要注意的是,由于模式匹配是按顺序匹配的,因此变量模式和通配符模式要写在表达式的最后面。

类型匹配模式

可以匹配输入变量的类型。

object TypePattern{
  def main(args:Array[String]) :Unit = {
  //类型匹配模式
  def typePattern(t : Any) = t match {
    case t : String => "String"
    case t : Int => "Intger"
    case t : Double => "Double"
    case _ => "Other Type"
   }
  }
}

case class模式

构造器模式指的是,直接在case语句后面接类构造器,匹配的内容放置在构造器参数中。

object CaseClassPattern{
  def main(args:Array[String]) :Unit = {
  //定义一个Person实例
  val p = new Person(“nyz”,27)
  //case class 模式
  def constructorPattern(p : Person) = p match {
     case Person(name,age) => “name =” + name + “,age =” + age
     case _ => “Other”
    }
  }
}

模式守卫

为了让匹配更加具体,可以使用模式守卫,也就是在模式后面加上if判断语句。

object ConstantPattern{
  def main(args:Array[String]) :Unit = {
    //模式匹配结果作为函数返回值
    def patternShow(x : Any) = x match {
        //模式守卫
        case x if(x == 5) => “守卫”
        //通配符模式
      case _ => “通配符”
    }
  }
}

Option匹配

在Scala中Option类型样例类用来表示可能存在或也可能不存在的值(Option的子类有Some和None)。Some包装了某个值,None表示没有值。

class OptionDemo {
  val map = Map ((“a”,18),(“b”,81))
  //get方法返回的类型就是Option[Int]
  map.get(“b”) match {
    case some(x) => println(x)
    case None => println(“不存在”)
  }
}

Scala Trait(特质)

Scala Trait(特质) 相当于 Java 的接口,但实际上它比接口的功能强大。与接口不同的是,它还可以定义属性和方法的实现。

一般情况下Scala的类只能够继承单一父类,但可以使用with关键字混入多个 Trait(特质) 。不过,如果一个scala类没有父类,那么它混入的第一个特质需要使用extends关键字,之后混入的特质使用with关键字。

Trait(特质) 定义的方式与类相似,但它使用的关键字是 trait,如下所示:

trait Equal {
  def isEqual(x: Any): Boolean
  def isNotEqual(x: Any): Boolean = !isEqual(x)
}

以上特质(Equal)由两个方法组成:isEqual 和 isNotEqual。isEqual 方法没有定义方法的实现,isNotEqual定义了方法的实现。子类继承特质可以实现未被实现的方法。

以下演示了特质的完整实例:

trait Equal {
  def isEqual(x: Any): Boolean
  def isNotEqual(x: Any): Boolean = !isEqual(x)
}

class Point(xc: Int, yc: Int) extends Equal {
  val x: Int = xc
  val y: Int = yc
  def isEqual(obj: Any) = obj.isInstanceOf[Point] && obj.asInstanceOf[Point].x == x
}

object Test {
  def main(args: Array[String]) {
    val p1 = new Point(2, 3)
    val p2 = new Point(2, 4)
    val p3 = new Point(3, 3)

    println(p1.isNotEqual(p2))
    println(p1.isNotEqual(p3))
    println(p1.isNotEqual(2))
  }
}

执行以上代码,输出结果为:

$ scalac Test.scala $ scala -cp . Test``false``true``true

集合操作

常用集合

以下代码演示了常用集合的创建方式:

// 定义整型 List,其元素以线性方式存储,可以存放重复对象。
val x = List(1,2,3,4)

// 定义 Set,其对象不按特定的方式排序,并且没有重复对象。
val x = Set(1,3,5,7)

// 定义 Map,把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象。
val x = Map("one" -> 1, "two" -> 2, "three" -> 3)

// 创建两个不同类型元素的元组,元组是不同类型的值的集合
val x = (10, "Bigdata")

// 定义 Option,表示有可能包含值的容器,也可能不包含值。
val x:Option[Int] = Some(5)

集合函数

在操作 Scala 集合时,一般会进行两类操作:转换操作(transformation)和行动操作(action)。第一种操作类型将集合转换为另一个集合,第二种操作类型返回某些类型的值。

1. 最大值和最小值

在序列中查找最大或最小值是一个极常见的需求。以下是一个简单的例子:

val numbers = Seq(11, 2, 5, 1, 6, 3, 9)
numbers.max //11
numbers.min //1

对于这种简单数据集合,Scala的函数式特性显露无疑,如此简单的取到了最大值和最小值。再来看一个数据集合复杂的例子:

case class Book(title: String, pages: Int)
val books = Seq(
  Book("Future of Scala developers", 85),
  Book("Parallel algorithms", 240),
  Book("Object Oriented Programming", 130),
  Book("Mobile Development", 495)
)

// 下面代码返回Book(Mobile Development,495)
books.maxBy(book => book.pages)

// 下面代码返回Book(Future of Scala developers,85)
books.minBy(book => book.pages)

minBy & maxBy方法解决了复杂数据的问题。

2. 筛选-Filter

对集合进行过滤,返回满足条件的元素的新集合,比如过滤一组数据中的偶数。

val numbers = Seq(1,2,3,4,5,6,7,8,9,10)
numbers.filter(n => n % 2 == 0) //上面返回Seq(2,4,6,8,10)

获取页数大于300页的书。

val books = Seq(
  Book("Future of Scala developers", 85),
  Book("Parallel algorithms", 240),
  Book("Object Oriented Programming", 130),
  Book("Mobile Development", 495)
)

books.filter(book => book.pages >= 300) //上面返回Seq(Book("Mobile Development", 495))

还有一个与 filter类似的方法是 filterNot,也就是筛选出不满足条件的对象。

3. Flatten

Flatten的作用是将多个集合展开,组成一个新的集合,举例说明。

val abcd = Seq('a', 'b', 'c', 'd')
val efgj = Seq('e', 'f', 'g', 'h')
val ijkl = Seq('i', 'j', 'k', 'l')
val mnop = Seq('m', 'n', 'o', 'p')
val qrst = Seq('q', 'r', 's', 't')
val uvwx = Seq('u', 'v', 'w', 'x')
val yz = Seq('y', 'z')
val alphabet = Seq(abcd, efgj, ijkl, mnop, qrst, uvwx, yz)

alphabet.flatten

执行后返回下面的集合:

List('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z')

4. 集合运算函数

集合运算即差集、交集和并集操作。

val num1 = Seq(1, 2, 3, 4, 5, 6)
val num2 = Seq(4, 5, 6, 7, 8, 9)

// 返回List(1, 2, 3)
num1.diff(num2)

// 返回List(4, 5, 6)
num1.intersect(num2)

// 返回List(1, 2, 3, 4, 5, 6, 4, 5, 6, 7, 8, 9)
num1.union(num2)

// 合并后再去重,返回List(1, 2, 3, 4, 5, 6, 7, 8, 9)
num1.union(num2).distinct

5. map函数

map 函数的逻辑是遍历集合并对每个元素调用传入的函数进行处理。

val numbers = Seq(1,2,3,4,5,6)
// 返回List(2, 4, 6, 8, 10, 12)
numbers.map(n => n * 2)

val chars = Seq('a', 'b', 'c', 'd')
// 返回List(A, B, C, D)
chars.map(ch => ch.toUpper)

6. flatMap

flatMap将map & flatten组合起来,以下是一个操作示例:

val abcd = Seq('a', 'b', 'c', 'd')
// 返回List(A, a, B, b, C, c, D, d)
abcd.flatMap(ch => List(ch.toUpper, ch))

从结果可以看出来是先做的map,然后做的flatten。

7. forall & exists

forall是对整个集合做判断,当集合中的所有元素都满足条件时,返回true。而exists则是只要有一个元素满足条件就返回true。

val numbers = Seq(3, 7, 2, 9, 6, 5, 1, 4, 2)

// 返回true
numbers.forall(n => n < 10)

// 返回false
numbers.forall(n => n > 5)

// 返回true
numbers.exists(n => n > 5)

读取数据源

读取外部数据源是开发中很常见的需求,如在程序中读取外部配置文件并解析,获取相应的执行参数。

以下是Scala通过Source类读取数据源的简单介绍:

import scala.io.Source

object ReadFile {
  // 读取ClassPath下的配置文件
  val file = Source.fromInputStream(this.getClass.getClassLoader.getResourceAsStream("app.conf"))

  // 一行一行读取文件,getLines()表示读取文件所有行
  def readLine: Unit ={
    for(line <- file.getLines()){
      println(line)
    }
  }

  // 读取网络上的内容
  def readNetwork: Unit ={
    val file = Source.fromURL("http://www.baidu.com")
    for(line <- file.getLines()){
      println(line)
    }
  }

  // 读取给定的字符串-多用于调试
  val source = Source.fromString("test")
}

隐式转换

隐式转换是Scala中一种非常有特色的功能,它可以实现将某种类型的对象转换为另一种类型的对象。在数据分析工作中,最常使用到的就是java和scala集合之间的互相转换,转换以后就可以调用另一种类型的方法。scala提供了scala.collection.JavaConversions类,只要引入此类中相应的隐式转化方法,在程序中就可以用相应的类型来代替要求的类型。

例如,通过以下转换,scala.collection.mutable.Buffer自动转换成了java.util.List。

import scala.collection.JavaConversions.bufferAsJavaList
// scala.collection.mutable.Buffer => java.util.List

同样,java.util.List也可以转换成scala.collection.mutable.Buffer。

import scala.collection.JavaConversions.asScalaBuffer
// java.util.List => scala.collection.mutable.Buffer

所有可能的转换汇总如下,双向箭头表示可互相转换,单箭头则表示只有左边可转换到右边。

import scala.collection.JavaConversions._

// scala.collection.Iterable <=> java.lang.Iterable
// scala.collection.Iterable <=> java.util.Collection
// scala.collection.Iterator <=> java.util.{ Iterator, Enumeration }
// scala.collection.mutable.Buffer <=> java.util.List
// scala.collection.mutable.Set <=> java.util.Set
// scala.collection.mutable.Map <=> java.util.{ Map, Dictionary }
// scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap

// scala.collection.Seq => java.util.List
// scala.collection.mutable.Seq => java.util.List
// scala.collection.Set => java.util.Set
// scala.collection.Map => java.util.Map
// java.util.Properties => scala.collection.mutable.Map[String, String]

隐式参数

所谓隐式参数,指的是在函数或者方法中,定义使用implicit修饰的参数。当调用该函数或方法时,scala会尝试在变量作用域中找到一个与指定类型相匹配的使用implicit修饰的对象,即隐式值,注入到函数参数中函数体使用。以下是一个示例:

class SayHello{
  def write(content:String) = println(content)
}
implicit val sayHello=new SayHello

def saySomething(name:String)(implicit sayHello:SayHello){
  sayHello.write("Hello," + name)
}

saySomething("Scala")
// 打印 Hello,Scala


文章来源地址https://www.toymoban.com/news/detail-850758.html

到了这里,关于Scala编程基础:表达式、函数、模式匹配与集合操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 正则表达式的匹配(py编程)

    1. 匹配单个字符 在上一小节中,了解到通过re模块能够完成使用正则表达式来匹配字符串 本小节,将要讲解正则表达式的单字符匹配 代码 功能 . 匹配任意1个字符(除了n) [ ] 匹配[ ]中列举的字符 d 匹配数字,即0-9 D 匹配非数字,即不是数字 s 匹配空白,即 空格,tab键

    2024年02月02日
    浏览(77)
  • 【Python】Python 模式匹配与正则表达式

    你可能熟悉文本查找,即按下Ctrl-F,输入你要查找的词。 “正则表达式”更进一步,它们让你指定要查找的“模式”。 你也许不知道一家公司的准确电话号码,但如果你住在美国或加拿大, 你就知道它有3位数字,然后是一个短横线,然后是4位数字(有时候以3位区号开始)

    2024年02月07日
    浏览(57)
  • java14 使用增强的模式匹配切换表达式

    野旷天低树,江清月近人。——唐代杜甫《月夜忆舍弟》 使用增强的模式匹配切换表达式(Switch Expressions with Enhanced Pattern Matching) Java 14中引入的“Switch Expressions with Enhanced Pattern Matching”这个功能。 这个功能可以让我们在使用switch case语句时,同时进行类型检查和类型转换,从

    2023年04月08日
    浏览(30)
  • Java 基础进阶篇(十八):正则表达式匹配规则和应用

      正则表达式是对字符串(包括普通字符(例如:a 到 z 之间的字母)和特殊字符(称为“元字符”))操作的一种逻辑公式,就是用事先定义好的一些特定字符及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。正

    2024年02月13日
    浏览(56)
  • 探索Python中的函数式编程:Lambda表达式与函数式工具【第135篇—Lambda表达式】

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 在Python编程世界中,函数式编程逐渐成为了一种流行的范式,特别是在处理数据和编写简洁、高效代码时。函数式编程的核心思想是将计算视

    2024年04月08日
    浏览(87)
  • Java 函数式编程与 Lambda 表达式

    2023年10月31日
    浏览(62)
  • Java8函数式编程(Lambda表达式)

    Lambda 表达式是一个匿名方法,将行为像数据一样进行传递。 Lambda 表达式的常见结构:BinaryOperatorInteger add = (x, y) → x + y。 函数接口指仅具有单个抽象方法的接口,用来表示 Lambda 表达式的类型。 Stream 是用函数式编程方式在集合类上进行复杂操作的工具。 这行代码并未做什

    2024年02月16日
    浏览(43)
  • Shell编程基础(十三)正则表达式

    格式:^ 表达式 $ 在不同的场景下,定义是一样,但使用要按照具体的命令去调用,中间的表达式都是通用的 普通元字符 所谓元数据,就是描述数据的数据,在这里就是描述正则的数据 ^ 表示正则从字符串 整行 起始位置匹配 ^abc 匹配 以abc开始的字符串 $ 表示正则一直匹配到

    2024年02月14日
    浏览(40)
  • 正则表达式 (用于灵活匹配文本的表达式)

    目录 . * 用于匹配任意单个字符,除了换行符。 例如使用正则表达式 a.b, 它可以匹配aab、acb、a#b 用于匹配前一个字符零次或多次。 例如,使用正则表达式 ab*c ,它可以匹配 \\\"ac\\\"、\\\"abc\\\"、\\\"abbc\\\",因为 b* 表示匹配零个或多个字符 \\\"b\\\"。所以,这个表达式可以匹配 \\\"ac\\\"(零个 \\\"b\\\"),

    2024年01月16日
    浏览(63)
  • 【Go 基础篇】Go语言匿名函数详解:灵活的函数表达式与闭包

    在Go语言中,函数是一等公民,这意味着函数可以像其他类型的值一样被操作、传递和赋值。匿名函数是一种特殊的函数,它没有固定的函数名,可以在代码中被直接定义和使用。匿名函数在Go语言中具有重要的地位,它们常用于实现闭包、函数式编程和并发编程等领域。 本

    2024年02月11日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包