scala学习之函数式风格编程(代码片段)

顧棟 顧棟     2022-12-22     569

关键词:

FUNCTIONAL PROGRAMMING

https://docs.scala-lang.org/overviews/scala-book/functional-programming.html

Scala 允许您以面向对象编程 (OOP) 风格、函数式编程 (FP) 风格甚至混合风格编写代码,结合使用这两种方法。本书假设您是从 Java、C++ 或 C# 等 OOP 语言来到 Scala 的,因此除了涵盖 Scala 类之外,本书中没有任何关于 OOP 的特殊部分。但是由于 FP 风格对于许多开发人员来说仍然相对较新,我们将在接下来的几课中简要介绍 Scala 对 FP 的支持。

函数式编程是一种强调仅使用纯函数和不可变值编写应用程序的编程风格。正如 Alvin Alexander 在 Functional Programming, Simplified 中所写,与其使用这种描述,不如说函数式程序员非常强烈地希望将他们的代码视为数学——将他们的函数组合视为一系列代数方程.在这方面,您可以说函数式程序员喜欢将自己视为数学家。这是导致他们只使用纯函数和不可变值的驱动力,因为这就是你在代数和其他形式的数学中使用的东西。

函数式编程是一个很大的主题,没有简单的方法可以将整个主题浓缩到这本小书中,但在接下来的课程中,我们将带您体验 FP,并展示 Scala 为开发人员编写函数式编程提供的一些工具代码。

PURE FUNCTIONS

https://docs.scala-lang.org/overviews/scala-book/pure-functions.html

Scala 提供的第一个帮助您编写函数式代码的功能是编写纯函数的能力。 在 Functional Programming, Simplified 中,Alvin Alexander 定义了一个像这样的纯函数:

  • 函数的输出取决于其输入变量
  • 它不会改变任何隐藏状态
  • 没有任何“后门”:不从外部读取数据(包括控制台、Web 服务、数据库、文件等),也不向外部写入数据

作为这个定义的结果,任何时候你用相同的输入值调用一个纯函数,你总是会得到相同的结果。 例如,您可以使用输入值“2”无限次调用“double”函数,并且始终会得到结果“4”。

Examples of pure functions

鉴于纯函数的定义,正如您想象的那样, scala.math._ 包中的这些方法是纯函数:

  • abs
  • ceil
  • max
  • min

这些 Scala String 方法也是纯函数:

  • isEmpty
  • length
  • substring

Scala 集合类上的许多方法也可以用作纯函数,包括 dropfiltermap

Examples of impure functions

相反,以下函数是不纯的,因为它们违反了定义。

集合类上的 foreach 方法是不纯的,因为它只用于它的副作用,例如打印到 STDOUT。

A great hint that foreach is impure is that it’s method signature declares that it returns the type Unit. Because it returns nothing, logically the only reason you ever call it is to achieve some side effect. Similarly, any method that returns Unit is going to be an impure function.

与日期和时间相关的方法,如 getDayOfWeek、getHour 和 getMinute 都是不纯的,因为它们的输出取决于输入参数以外的其他东西。 在这些示例中,他们的结果依赖于某种形式的隐藏 I/O,隐藏输入

一般而言,不纯函数执行以下一项或多项操作:

  • 读取隐藏的输入,即它们访问未作为输入参数显式传递给函数的变量和数据
  • 写隐藏的输出
  • 改变给定的参数
  • 与外界执行某种 I/O

But impure functions are needed …

当然,如果一个应用程序不能读取或写入外部世界,它就不是很有用,所以人们提出这个建议:

使用纯函数编写应用程序的核心,然后围绕该核心编写一个不纯的“包装器”以与外部世界交互。 如果你喜欢食物类比,这就像在纯蛋糕上放一层不纯的糖霜。

有一些方法可以让与外界的不纯洁的互动感觉更纯洁一些。 例如,您会听到诸如用于处理用户输入、文件、网络和数据库的“IO”Monad 之类的东西。 但最终,FP 应用程序有一个核心的纯函数结合其他函数来与外界交互。

Writing pure functions

在 Scala 中编写纯函数是函数式编程中比较简单的部分之一:您只需使用 Scala 的方法语法编写纯函数即可。 这是一个将给定的输入值加倍的纯函数:

def double(i: Int): Int = i * 2

虽然本书没有涉及递归,但如果你喜欢一个好的“挑战”示例,这里有一个计算整数列表总和的纯函数(List[Int]):

def sum(list: List[Int]): Int = list match 
    case Nil => 0
    case head :: tail => head + sum(tail)

即使我们没有涉及递归,如果你能理解这段代码,你就会发现它符合我对纯函数的定义。

Key points

本课的第一个重点是纯函数的定义:

A 纯函数 是一个仅依赖于其声明的输入和其内部算法来产生其输出的函数。 它不会从“外部世界”(函数作用域之外的世界)读取任何其他值,也不会修改外部世界中的任何值。

第二个关键点是现实世界的应用程序由纯函数和非纯函数的组合组成。 一个常见的建议是使用纯函数编写应用程序的核心,然后使用非纯函数与外界进行通信。

PASSING FUNCTIONS AROUND

https://docs.scala-lang.org/overviews/scala-book/passing-functions-around.html

虽然曾经创建的每种编程语言都可能允许您编写纯函数,但 Scala 的第二个伟大的 FP 特性是您可以将函数创建为变量,就像创建 String 和 Int 变量一样。 这个特性有很多好处,其中最常见的是它可以让你将函数作为参数传递给其他函数。 您在本书前面演示 map 和 filter 方法时看到了这一点:

val nums = (1 to 10).toList

val doubles = nums.map(_ * 2)
val lessThanFive = nums.filter(_ < 5)

在这些示例中,匿名函数被传递到 mapfilter。 在匿名函数的课程中,我们演示了这个例子:

val doubles = nums.map(_ * 2)

与将常规函数传递给 map 相同:

def double(i: Int): Int = i * 2   //a method that doubles an Int
val doubles = nums.map(double)

正如这些示例所示,Scala 清楚地允许您将匿名函数和常规函数传递给其他方法。 这是优秀的 FP 语言提供的强大功能。

如果您喜欢技术术语,则将另一个函数作为输入参数的函数称为 高阶函数 (HOF)。 (如果你喜欢幽默,就像有人曾经写过的那样,这就像说一个将另一个类的实例作为构造函数参数的类是一个高阶类。)

Function or method?

Scala 有 一种特殊的“函数”语法,但实际上,def 语法似乎更受欢迎 . 这可能是由于两个原因:

  • 有 C/Java/C# 背景的人更熟悉 def 语法
  • 你可以像使用 val 函数一样使用 def 方法

第二个语句的意思是,当你像这样用 def 定义一个方法时:

def double(i: Int): Int = i * 2

you can then pass double around as if it were a variable, like this:

val x = ints.map(double)
                 ------

尽管 double 被定义为 method,Scala 允许你将其视为 function

将函数作为变量传递的能力是函数式编程语言的一个显着特征。 正如您在本书的 mapfilter 示例中所见,将函数作为参数传递给其他函数的能力有助于您创建简洁且可读的代码。

A few examples

如果您对将函数作为参数传递给其他函数的过程不满意,以下是您可以在 REPL 中试验的更多示例:

List("foo", "bar").map(_.toUpperCase)
List("foo", "bar").map(_.capitalize)
List("adam", "scott").map(_.length)
List(1,2,3,4,5).map(_ * 10)
List(1,2,3,4,5).filter(_ > 2)
List(5,1,3,11,7).takeWhile(_ < 6)

请记住,这些匿名函数中的任何一个也可以编写为“常规”函数,因此您可以编写如下函数:

def toUpper(s: String): String = s.toUpperCase

然后像这样将它传递给map

List("foo", "bar").map(toUpper)

或这个:

List("foo", "bar").map(s => toUpper(s))

那些使用“常规”函数的示例等效于这些匿名函数示例:

List("foo", "bar").map(s => s.toUpperCase)
List("foo", "bar").map(_.toUpperCase)

NO NULL VALUES

https://docs.scala-lang.org/overviews/scala-book/no-null-values.html

函数式编程就像编写一系列代数方程,因为在代数中不使用空值,所以在 FP 中也不使用空值。 这就引出了一个有趣的问题:在您通常在 Java/OOP 代码中使用空值的情况下,您会怎么做?

Scala 的解决方案是使用类似 Option/Some/None 类的结构。 我们将在本课中介绍这些技术。

A first example

虽然第一个 Option/Some/None 示例不处理空值,但它是演示 Option/Some/None 类的好方法,因此我们将从它开始。

想象一下,您想编写一个方法来轻松将字符串转换为整数值,并且您想要一种优雅的方式来处理当您的方法获取像“foo”这样的字符串而不是转换的东西时可能抛出的异常 到一个数字,比如“1”。 对此类函数的初步猜测可能如下所示:

def toInt(s: String): Int = 
    try 
        Integer.parseInt(s.trim)
     catch 
        case e: Exception => 0
    

这个函数的想法是,如果字符串转换为整数,则返回转换后的 Int,但如果转换失败,则返回 0。这对于某些目的来说可能没问题,但并不准确。 例如,该方法可能收到了“0”,但它也可能收到了“foo”或“bar”或无数其他字符串。 这就产生了一个真正的问题:你怎么知道这个方法什么时候真正收到了“0”,或者什么时候收到了别的东西? 答案是,使用这种方法,无法知道。

Using Option/Some/None

Scala 解决这个问题的方法是使用三个类,称为OptionSomeNoneSomeNone 类是 Option 的子类,因此解决方案如下所示:

  • 你声明 toInt 返回一个 Option 类型
  • 如果toInt 收到一个字符串,它可以 转换为Int,则将Int 包装在Some
  • 如果 toInt 收到一个它不能转换的字符串,它返回一个 None

解决方案的实现如下所示:

def toInt(s: String): Option[Int] = 
    try 
        Some(Integer.parseInt(s.trim))
     catch 
        case e: Exception => None
    

这段代码可以读作,“当给定的字符串转换为整数时,返回包裹在Some包装器中的整数,例如Some(1)。 当字符串无法转换为整数时,返回一个 None 值。”

下面是两个演示 toInt 实际操作的 REPL 示例:

scala> val a = toInt("1")
a: Option[Int] = Some(1)

scala> val a = toInt("foo")
a: Option[Int] = None

如图所示,字符串1转换为Some(1),字符串foo转换为None。 这是 Option/Some/None 方法的本质。 它用于处理异常(如本例所示),同样的技术也适用于处理空值。

您会发现这种方法在整个 Scala 库类和第三方 Scala 库中都有使用。

Being a consumer of toInt

现在假设您是 toInt 方法的使用者。 您知道该方法返回 Option[Int] 的子类,所以问题变成了,您如何处理这些返回类型?

根据您的需要,有两个主要答案:

  • 使用“匹配”表达式
  • 使用 for 表达式

还有其他方法,但这是两种主要方法,尤其是从 FP 的角度来看。

Using a match expression

一种可能性是使用 match 表达式,如下所示:

toInt(x) match 
    case Some(i) => println(i)
    case None => println("That didn't work.")

在这个例子中,如果 x 可以转换为 Int,则执行第一个 case 语句; 如果 x 无法转换为 Int,则执行第二个 case 语句。

Using for/yield

另一种常见的解决方案是使用 for 表达式——即本书前面展示的 for/yield 组合。 为了演示这一点,假设您要将三个字符串转换为整数值,然后将它们相加。 for/yield 解决方案如下所示:

val y = for 
    a <- toInt(stringA)
    b <- toInt(stringB)
    c <- toInt(stringC)
 yield a + b + c

当该表达式完成运行时,y 将是以下两种情况之一:

  • 如果所有三个字符串都转换为整数,y 将是一个 Some[Int],即一个包裹在 Some 中的整数
  • 如果三个字符串中的任何一个无法转换为内部,y 将是一个 None

您可以在 Scala REPL 中自行测试。 首先,将这三个字符串变量粘贴到 REPL 中:

val stringA = "1"
val stringB = "2"
val stringC = "3"

接下来,将 for 表达式粘贴到 REPL 中。 当你这样做时,你会看到这个结果:

scala> val y = for 
     |     a <- toInt(stringA)
     |     b <- toInt(stringB)
     |     c <- toInt(stringC)
     |  yield a + b + c
y: Option[Int] = Some(6)

如图所示,y 绑定到值 Some(6)

要查看失败情况,请将这些字符串中的任何一个更改为不会转换为整数的内容。 当你这样做时,你会看到 y 是一个 None

y: Option[Int] = None

Options can be thought of as a container of 0 or 1 items

考虑 Option 类的一种好方法是它们代表一个 container,更具体地说是一个容器,里面有零个或一个项目:

  • Some 是一个容器,里面有一个项目
  • None 是一个容器,但里面什么都没有

If you prefer to think of the Option classes as being like a box, None is a little like getting an empty box for a birthday gift.

Using foreach

因为 SomeNone 可以被认为是容器,它们可以进一步被认为类似于集合类。 因此,它们拥有您期望从集合类中获得的所有方法,包括 mapfilterforeach 等。

这提出了一个有趣的问题:如果有的话,这两个值将打印什么?

toInt("1").foreach(println)
toInt("x").foreach(println)

答案是第一个示例打印数字“1”,第二个示例不打印任何内容。 第一个示例打印“1”,因为:

  • toInt(“1”) 评估为Some(1)
  • 表达式计算为Some(1).foreach(println)
  • Some 类上的 foreach 方法知道如何到达 Some 容器内部并提取其中的值 (1),因此它将该值传递给 println

同样,第二个示例不打印任何内容,因为:

  • toInt("x") evaluates to None
  • None 类上的 foreach 方法知道 None 不包含任何内容,因此它什么都不做

Again, None is just an empty container.

在 Scala 历史的某个地方,有人注意到第一个例子(Some)代表了 Option/Some/None 方法的“Happy Path”,而第二个例子(None)代表了“Unhappy Path”。 但是,尽管有两种不同的可能结果,但这种方法很酷的一点是,您编写的用于处理Option的代码在两种情况下看起来完全相同。 foreach 示例如下所示:

toInt("1").foreach(println)
toInt("x").foreach(println)

for 表达式如下所示:

val y = for 
    a <- toInt(stringA)
    b <- toInt(stringB)
    c <- toInt(stringC)
 yield a + b + c

您只需要编写一段代码来处理快乐和不快乐路径,这会简化您的代码。 唯一需要考虑是得到 Some 还是 None 的时候是当你最终在 match 表达式中处理结果值时,如下所示:.

toInt(x) match 
    case Some(i) => println(i)
    case None => println("That didn't work.")

Using Option to replace null values

另一个空值可以悄悄潜入您的代码的地方是这样的类:

class Address (
    var street1: String,
    var street2: String,
    var city: String, 
    var state: String, 
    var zip: String
)

虽然地球上的每个地址都有一个 street1 值,而 street2 值是可选的。 因此,该类会受到这种类型的滥用:

val santa = new Address(
    "1 Main Street",
    null,               // <-- D'oh! A null value!
    "North Pole",
    "Alaska",
    "99705"
)

为了处理这样的情况,开发人员倾向于使用空值或空字符串,这两者都是解决主要问题的技巧:street2 是一个可选字段。 在 Scala 和其他现代语言中,正确的解决方案是预先声明 street2 是可选的:

class Address (
    var street1: String,
    var street2: Option[String],
    var city: String, 
    var state: String, 
    var zip: String
)

有了这个定义,开发人员可以编写更准确的代码,如下所示:

val santa = new Address(
    "1 Main Street",
    None,
    "North Pole",
    "Alaska",
    "99705"
)

or this:

val santa = new Address(
    "123 Main Street",
    Some("Apt. 2B"),
    "Talkeetna",
    "Alaska",
    "99676"
)

一旦你有了这样的可选字段,你就可以像前面的例子一样使用它:使用 match 表达式、for 表达式和其他内置方法,如 foreach

Option isn’t the only solution

本课重点介绍 Option/Some/None 解决方案,但 Scala 有其他一些替代方案。 例如,称为 Try/Success/Failure 的三个类以相同的方式工作,但是 a) 当代码可以抛出异常时,您主要使用这些类,并且 b) Failure 类使您可以访问异常消息。 例如,在编写与文件、数据库和 Internet 服务交互的方法时,通常会使用 Try/Success/Failure,因为这些函数很容易抛出异常。 这些类在随后的功能错误处理课程中进行了演示。

Key points

这节课比其他课长一点,所以这里是要点的快速回顾:

  • 函数式程序员不使用空值
  • 空值的主要替代品是使用 Option/Some/None 类
  • 使用 Option 值的常用方法是 matchfor 表达式
  • 选项可以被认为是一个项目(Some)和没有项目(None)的容器
  • 您还可以在定义构造函数参数时使用选项

COMPANION OBJECTS

https://docs.scala-lang.org/overviews/scala-book/companion-objects.html

Scala 中的伴生对象是在与类相同的文件中声明的对象,并且与类具有相同的名称。 例如,当以下代码保存在名为 Pizza.scala 的文件中时,Pizza 对象被认为是 Pizza 类的伴随对象:

class Pizza 


object Pizza 

这有几个好处。 首先,伴随对象及其类可以访问彼此的私有成员(字段和方法)。 这意味着此类中的 printFilename 方法将起作用,因为它可以访问其伴生对象中的 HiddenFilename 字段:

class SomeClass 
    def printFilename() = 
        println(SomeClass.HiddenFilename)
    


object SomeClass 
    private val HiddenFilename = "/tmp/foo.bar"

伴随对象提供了比这更多的功能,我们将在本课的其余部分演示它的一些最重要的功能。

Creating new instances without the new keyword

您可能在本书的一些示例中注意到,您可以创建某些类的新实例,而无需在类名前使用 new 关键字,如下例所示:

val zenMasters = List(
    Person("Nansen"),
    Person("Joshu")
)

此功能来自于伴随对象的使用。 发生的情况是,当您在伴生对象中定义“apply”方法时,它对 Scala 编译器具有特殊意义。 Scala 中有一些语法糖,可以让您键入以下代码:

val p = Person("Fred Flinstone")

在编译过程中,编译器将该代码转换为以下代码:

val p = Person.apply("Fred Flinstone")

伴随对象中的 apply 方法充当 工厂方法,Scala 的语法糖允许您使用所示的语法,创建新的类实例,而无需使用 new 关键字。

Enabling that functionality

为了演示这个特性是如何工作的,这里有一个名为 Person 的类以及它的伴生对象中的 apply 方法:

class Person 
    var name = ""


object Person 
    def apply(name: String): Person = 
        var p = new Person
        p.name = name
        p
    

要测试此代码,请使用以下技术将类和对象同时粘贴到 Scala REPL 中:

  • 从命令行启动 Scala REPL(使用 scala 命令)
  • 输入 :paste 并按 [Enter] 键
  • REPL 应回复此文本:
// Entering paste mode (ctrl-D to finish)
  • 现在将类和对象同时粘贴到 REPL 中
  • 按 Ctrl-D 完成“粘贴”过程

当该过程工作时,您应该在 REPL 中看到以下输出:

defined class Person
defined object Person

The REPL requires that a class and its companion object be entered at the same time with this technique.

现在你可以像这样创建一个 Person 类的新实例:

val p = Person.apply("Fred Flinstone")

该代码直接调用伴随对象中的“apply”。 更重要的是,您还可以像这样创建一个新实例:

val p = Person("Fred Flinstone")

and this:

val zenMasters = List(
    Person("Nansen"),
    Person("Joshu")
)

需要说明的是,这个过程中发生的事情是:

  • 你输入类似val p = Person("Fred")
  • Scala 编译器发现Person 之前没有new 关键字
  • 编译器在“Person”类的伴生对象中查找与您输入的类型签名匹配的“apply”方法
  • 如果它找到一个 apply 方法,它就会使用它; 如果没有,你会得到一个编译器错误

Creating multiple constructors

你可以在一个伴生对象中创建多个 apply 方法来提供多个构造函数。 以下代码显示了如何创建单参数和双参数构造函数。 因为我们在上一课中介绍了 Option 值,这个例子也展示了如何在这样的情况下使用 Option

class Person 
    var name: Option[String] = None
    var age: Option[Int] = None
    override def toString = s"$name, $age"


object Person 

    // a one-arg constructor
    def apply(name: Option[String]): Person = 
        var p = new Person
        p.name = name
        p
    

    // a two-arg constructor
    def apply(name: Option[String], age: Option[Int]): Person = 
        var p = new Person
        p.name = name
        p.age = age
        p
    


如果像以前一样将该代码粘贴到 REPL 中,您将看到可以像这样创建新的 Person 实例:

val p1 = Person(Some("Fred"))
val p2 = Person(None)

val p3 = Person(Some("Wilma"), Some(33))
val p4 = Person(Some("Wilma"), None)

当您打印这些值时,您将看到以下结果:

val p1: Person = Some(Fred), None
val p2: Person = None, None
val p3: Person = Some(Wilma), Some(33)
val p4: Person = Some(Wilma), None

在运行这样的测试时,最好清除 REPL 的内存。 要做到这一点,在使用 :paste 命令之前,在 REPL 中使用 :reset 命令。

Adding an unapply method

就像在伴生对象中添加 apply 方法可以让您构造新的对象实例一样,添加unapply 可以让您解构对象实例。 我们将通过一个例子来证明这一点。

这是一个不同版本的 Person 类和一个伴生对象:

class Person(var name: String, var age: Int)

object Person 
    def unapply(p: Person): String = s"$p.name, $p.age"

请注意,伴随对象定义了一个 unapply 方法。 该方法接受一个Person类型的输入参数,并返回一个String。 要手动测试 unapply 方法,首先创建一个新的 Person 实例:

val p = new Person("Lori", 29)

然后像这样测试unapply

val result = Person.unapply(p)

这就是 REPL 中 unapply 结果的样子:

scala> val result = Person.unapply(p)
result: String = Lori, 29

如图所示,unapply 解构了它给定的 Person 实例。 在 Scala 中,当你将一个 unapply 方法放入一个伴生对象时,就表示你已经创建了一个 extractor 方法,因为你已经创建了一种从对象中提取字段的方法。

unapply can return different types

In that example unapply returns a String, but you can write it to return anything. Here’s an example that returns the two fields in a tuple:

class Person(var name: String, var age: Int)

object Person 
    def unapply(p: Person): Tuple2[String, Int] = (p.name, p.age)

Here’s what that method looks like in the REPL:

scala> val result = Person.unapply(p)
result: (String, Int) = (Lori,29)

Because this unapply method returns the class fields as a tuple, you can also do this:

scala> val (name, age查看详情  

前端学习之函数式编程—高阶函数(代码片段)

 什么是高阶函数(Higher-orderfunction)    可以把函数作为参数传递给另一个函数    可以把函数作为另一个函数的返回结果Part1可以把函数作为参数传递给另一个函数实现forEach函数//高阶函数-函数作为参数functionforEach(array,fn)for(... 查看详情

前端学习之函数式编程—柯里化(代码片段)

part01--柯里化概念柯里化是为了解决函数中不纯函数或函数硬编码的问题什么是硬编码functiongetAge(age)letmin=18returnage>min 函数式编程是保证相同的调用总能得到相同的结果,但当相同的调用有可能不能得到相同的结果时则... 查看详情

前端学习之函数式编程—函数组合(代码片段)

Part01函数组合纯函数和柯里化很容易写出洋葱代码=====>h(g(f(x)))一层一层套起来不宜阅读例如:获取数组最后的一个元素再转大写字母_.toUpper(_.first(_.reverse(array)))函数组合可以让我们把细粒度的函数重新组成... 查看详情

前端学习之函数式编程—纯函数(代码片段)

Part01纯函数概念纯函数:相同的输入永远会得到相同的输出,而且没有任何可观察的副作用纯函数就类似数学中的函数,用来描述输入与输出之间的关系,例如:y=f(x)Part02案例:slice和splice函数 数组的slice和splice分别是纯函数和不纯... 查看详情

spark学习之scala编程

 一、Scala语言基础1、Scala语言简介Scala是一种多范式的编程语言,其设计的初衷是要集成面向对象编程和函数式编程的各种特性。Scala运行于Java平台(Java虚拟机),并兼容现有的Java程序。学习Scala编程语言,为后续学习Spark... 查看详情

scala深入学习之函数学习(代码片段)

目录一、函数的定义二、匿名函数三、递归函数四、无参函数五、方法和函数的区别联系一、函数的定义代码示例:packagefunctionDemo/***@author:蔡政洁*@email:caizhengjie888@icloud.com*@date:2020/8/23*@time:2:14下午*/objectFunction... 查看详情

大数据学习之scala语言基本语法学习36

一:scala简介官网:https://www.scala-lang.org/Scala语言很强大,集成了面向对象和函数式编程的特点。运行在JVM(jdk)。大数据中为什么学习scala?spark是scala语言编写。python写spark挺好的java写spark很糟糕(代码实在是太多了)scala写spark很... 查看详情

scala语言学习之环境安装

==> Scala语言简介        --> Scala编程语言抓住了很多开发者的眼球。如果你粗略浏览Scala的网站,你会觉得Scala是一种纯粹的面向对象编程语言,而又无缝地结合了命令式编程和函数式编程... 查看详情

scala学习之scala集合类(代码片段)

文章目录SCALACOLLECTIONSThemainScalacollectionsclassesTHEARRAYBUFFERCLASSMorewaystoworkwith`ArrayBuffer`THELISTCLASSCreatingListsAddingelementstoaListHowtorememberthemethodnamesHowtoloopoverlistsA 查看详情

scala学习之scala快速入门(代码片段)

文章目录Scala的“味道”Overview概述Hello,worldTheScalaREPLTwotypesofvariablesDeclaringvariabletypesControlstructuresif/elsematchexpressionstry/catchforloopsandexpressionswhileanddo/whileClassesScalamethodsTraits 查看详情

scala学习之scala中的类(代码片段)

文章目录SCALACLASSESBasicclassconstructor`val`makesfieldsread-onlyClassconstructorsOtherScalaclassexamplesAUXILIARYCLASSCONSTRUCTORSNotesSUPPLYINGDEFAULTVALUESFORCONSTRUCTORPARAMETERSBenefitsBonus 查看详情

scala学习(函数式编程面向对象编程)(代码片段)

文章目录函数式编程基础函数编程函数定义函数参数函数至简原则高阶函数编程面向对象编程基础面向对象编程高阶面向对象编程函数式编程基础函数编程函数定义packagelearn03objectdemo01defmain(args:Array[String]):Unit=//无参、无返回... 查看详情

scala学习(函数式编程面向对象编程)(代码片段)

文章目录函数式编程基础函数编程函数定义函数参数函数至简原则高阶函数编程面向对象编程基础面向对象编程高阶面向对象编程函数式编程基础函数编程函数定义packagelearn03objectdemo01defmain(args:Array[String]):Unit=//无参、无返回... 查看详情

scala函数式编程(代码片段)

Scala函数式编程什么是函数式编程?1、函数式编程将计算视为数学上的函数计算2、函数成为了和普通的值一样的"头等公民",可以像任何其他数据类型的值一样被传递和操作函数式编程成为越来越流行的编程范式1... 查看详情

scala函数式编程函数式的数据结构下(代码片段)

前情提要Scala函数式编程指南(一)函数式思想介绍scala函数式编程(二)scala基础语法介绍Scala函数式编程(三)scala集合和函数Scala函数式编程(四)函数式的数据结构上1.List代码解析今天介绍的内容,主要是对上一篇介绍的sca... 查看详情

scala函数式编程函数式的错误处理(代码片段)

前情提要Scala函数式编程指南(一)函数式思想介绍scala函数式编程(二)scala基础语法介绍Scala函数式编程(三)scala集合和函数Scala函数式编程(四)函数式的数据结构上Scala函数式编程(四)函数式的数据结构下1.面向对象的... 查看详情

scala笔记整理:函数式编程(代码片段)

[TOC]作为值传递的函数测试代码如下:packagecn.xpleaf.bigdata.p4.function/***scala中关于函数的操作*/object_01FunctionOpsdefmain(args:Array[String]):Unit=functionOps1/***作为值传递的函数*将一个函数作为值传递给另外一个函数变量的时候,约定需要在... 查看详情