返回顶部
首页 > 资讯 > 精选 >如何理解Scala的核心规则
  • 491
分享到

如何理解Scala的核心规则

2023-06-17 08:06:47 491人浏览 安东尼
摘要

这篇文章将为大家详细讲解有关如何理解Scala的核心规则,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Read Eval Print Loop (REPL)REPL在Scala里面指的是直接

这篇文章将为大家详细讲解有关如何理解Scala的核心规则,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

Read Eval Print Loop (REPL)

REPL在Scala里面指的是直接运行scala.exe进入的交互式命令行模式。广义上讲,也泛指那些在线编程工具

核心规则1:请使用REPL来熟悉Scala语言。

Scala的REPL有个好处是能够将我们输入的每行代码的内部表示反馈出来。比如:

scala> def add(a:Int, b:Int):Int = a + b

add: (a: Int, b: Int)Int

我们定义一个函数,完成两个数的加法。Scala回显给我们的内容可以帮助我们写代码。

表达式与语句

表达式与语句的区别是:语句是用来执行的,而表达式是用来求值的。在程序员的世界里,表达式就是返回值,语言就是没有返回值执行程序。

Scala是表达式导向的编程语言。但并不是100%成立,Scala代码中还是有控制语块,毕竟我们写程序就是为了控制各种实体为我们服务的。

核心规则2:使用表达式,而不是语句。

这条规则主要是帮助我们简化代码,就像前面加法的例子,a+b就是一个表达式。相比于我们C语言写的相同实现,简单不好。代码里面,像这样的例子肯定还是存在很多的。

不要使用Return

当我们使用表达式的时候,就不需要Return了。因为表达式本身就是用来求值的,我们必要再去显式地说我现在要返回什么。Scala编译器自动使用***一个表达式的返回值作为函数的返回值。

我们应该记得一个编程指导意见就是函数在同一个地方返回。如果我们现在没有Return语句了,像在Scala中,有没有类似的编程指导呢?看个例子:

object NoReturn extends scala.App {    def createErrORMessage1(errorCode : Int) : String = {      val result = errorCode match {        case 1 => "Network Failure"       case 2 => "I/O Failure"       case 3 => "Unknown Error"     }      return result    }    def createErrorMessage2(errorCode: Int) : String = {      var result : String = null            // not val      errorCode match {        case 1 =>          result = "Network Failure"       case 2 =>          result = "I/O Failure"       case _ =>          result = "Unknown Error"     }      return result;    }    def createErrorMessage3(errorCode : Int) : String = {      errorCode match {        case 1 => "Network Failure"       case 2 => "I/O Failure"       case 3 => "Unknown Error"     }    }    println(createErrorMessage1(1))    println(createErrorMessage2(2))    println(createErrorMessage3(3))    println(1 match{case 1 => "Network Failure" case 2 => 3})    println(2 match{case 1 => "Network Failure" case 2 => 3})  }

createErrorMessage2应该是我们以往的写法。定义一个局部变量,然后匹配errorCode,对其进行赋值。createErrorMessage1是Scala推荐的写法(虽然还不够简洁),它使用的是val而不是var,来声明临时变量。val表示值,赋值后就不允许再更改;var是变量,可以重复赋值。createErrorMessage1的的result之后是一个表达式。求值之后直接就赋值了。createErrorMessage3就更加简洁了,差不多到了***形态了。函数直接就返回一个表达式,少了临时对象。

注:match case支持每个分支返回的类型不同。这个特性在函数式编程中非常有用。

Scala虽然支持所有的3中写法,但是推荐***一种。因为它帮助简化了代码的复杂度,增加了程序的不可变性。不可变指的是程序在执行过程中,所有的状态(变量)都是常量。不可变的代码比可变代码更加容易理解、调试和维护。

表达式导向的语言倾向与使用不可变的对象,能减少程序中的可变对象。

使用不可变对象

核心规则3:使用不可变对象可以大幅减少运行时故障。当面对可变与不可变的选择时,选择不可变对象无疑是最安全的。

对象等价性

Scala提供了##和==来判断对象是不是等价,它们可以作用于AnyRef(引用)和AnyVal(值)。

对象的哈希值和equal应该成对出现。因为等价性经常使用到了hash值。

import collection.immutable.HashMap  class Point2(var x: Int, var y: Int) extends Equals {    def move(mx: Int, my: Int) : Unit = {      x = x + mx      y = y + my    }    override def hashCode(): Int = y + (31*x)    def canEqual(that: Any): Boolean = that match {      case p: Point2 => true     case _ => false   }    override def equals(that: Any): Boolean = {      def strictEquals(other: Point2) =        this.x == other.x && this.y == other.y      that match {        case a: AnyRef if this eq a => true       case p: Point2 => (p canEqual this) && strictEquals(p)        case _ => false     }    }  }  object ObjecteEquality extends scala.App  {    val x = new Point2(1,1)    val y = new Point2(1,2)    val z = new Point2(1,1)    println(x == y) // false    println(x == z) // true    val map = HashMap(x -> "HAI", y -> "ZOMG")    println(map(x)) // HAI    println(map(y)) // ZOMG    println(map(z)) // HAI, if we remove hashCode, there will be an exception    x.move(1,1)  // println(map(x)) //Exception in thread "main" java.util.NoSuchElementException: key not found: Point2@40    println(map.find(_._1 == x))  }

3-22行定义了一个Point2类,它继承自Equals。

trait Equals extends Any {     def canEqual(that: Any): Boolean     def equals(that: Any): Boolean   }

定义了自己的move方法和hashCode方法。canEqual用来判断是否可以在对象上应用equal方法,这里只是检查是否类型匹配。equal包含一个内部函数strictEquals用来判断对象的成员是否相等。equal首先检查是不是引用了同一个Point2对象,如果是,直接返回true。否则,检查类型是不是匹配,如果是,用strictEquals用来判断对象的成员是否相等。

第36行:println(map(z)),它的正确执行依赖于hashCode是否定义。Map在寻找指定key的值的时候,会调用key.##。

第38行,由于move改变了x的内部状态,hashCode计算出来的新值当做key去Map里面查找,找不到对应的值,就会报NoSuchElementException异常。

第40行,比较奇特。看下find的定义:

trait IterableLike:

override  def find(p: A => Boolean): Option[A] = iterator.find(p)

object Iterator:

def find(p: A => Boolean): Option[A] = {    var res: Option[A] = None    while (res.isEmpty && hasNext) {      val e = next()      if (p(e)) res = Some(e)    }    res  }

传给find的是一个predicate。迭代器遍历集合中的每个元素,并将该元素作为参数传给predicate。所有我们这里传给predicate的参数是一个键值对[A,B]。_就是传给predicate的参数。_1指的是键值对中的***个元素(实际上是元组中的***个元素),即A,也就是作为key的Point2。现在很容易明白这句的意思了,就是与x的hashCode一样的元素。_1的定义位于:

trait Product2:

   def _1: T1

在我们实现对象的等价判断的时候,请遵循:

  • 如果两个对象相等,那它们应该有相同的hashCode。

  • 对象的hashCode在其生命周期内不会改变。

  • 如果将一个对象发送给其他的JVM,应该保证等价判断依赖于对象在两个JVM都可用的属性。主要用于序列化。

如果我们的对象是不可变的,那么上面的条件2自行就满足了,这会简化等价判断。另外,不可变性不仅仅简化等价判断,也会简化并行数据的访问,因为不存在同步互斥。

使用None而不是null

null的使用还是很受大家诟病的。null迫使大家添加了额外的处理代码。Scala使用Option来包装了null的处理,我们不在需要去判断变量是否为空。我们可以将Option看成一个通用的容器,包含了一些对象的容器(Some),或者是空容器(None)。这两周容器都需要对象的类型。

类似地,Scala还有空的列表Nil。

核心规则4:使用None而不是null

Java中,我们经常会碰到空异常。如果我们学会了正确使用Option,完全可以避免空异常的发生。

Scala的Option伴生对象(compaNIOn object)包含一个工厂方法,将Java的null自动转换为None:var x : Option[String] = Option(null)。等价于var x : Option[String] = Null。

Scala更加高级的用法是把它当作一个集合。这意味着,你可以在Option上使用map、flatMap、foreach,甚至是for表达式。

使用Null的一些高级实例:

class httpsession  class Connection  object DriverManager {    def getConnection(url: String, user: String, pw: String): Connection = {      println("getConnection")      new Connection    }  }  object AdvancedNull extends scala.App {    //CREATE AN OBJECT OR RETURN A DEFAULT    def getTemporaryDirectory(tmpArg: Option[String]): java.io.File = {      tmpArg.map(name => new java.io.File(name)).        filter(_.isDirectory).        getOrElse(new java.io.File(        System.getProperty("java.io.tmpdir")))    }    //EXECUTE BLOCK OF CODE IF VARIABLE IS INITIALIZED    val username1: Option[String] = Option("Sulliy")    for (uname <- username1) {      println("User: " + uname)    }    val username2: Option[String] = None    for (uname <- username2) {      println("User: " + uname)    }    def canAuthenticate(username: String, passWord: Array[Char]): Boolean = {      println("canAuthenticate")      true   }    def privilegesFor(username: String): Int = {      println("privilegesFor")      0   }    def injectPrivilegesIntoSession(session: HttpSession, privileges: Int): Unit = {      println("injectPrivilegesIntoSession")    }    def authenticateSession(session: HttpSession,                            username: Option[String],                            password: Option[Array[Char]]) = {      for (u <- username;           p <- password;           if canAuthenticate(u, p)) {        val privileges = privilegesFor(u)        injectPrivilegesIntoSession(session, privileges)      }    }    authenticateSession(new HttpSession, None, None)    //USING POTENTIAL UNINITIALIZED VARIABLES TO CONSTRUCT ANOTHER VARIABLE    def createConnection(conn_url: Option[String],                         conn_user: Option[String],                         conn_pw: Option[String]): Option[Connection] =      for {        url <- conn_url        user <- conn_user        pw <- conn_pw      } yield DriverManager.getConnection(url, user, pw)    createConnection(None, Option("sully"), None)    def lift3[A, B, C, D](f: Function3[A, B, C, D]): Function3[Option[A], Option[B], Option[C], Option[D]] = {      (oa: Option[A], ob: Option[B], oc: Option[C]) =>        for (a <- oa; b <- ob; c <- oc) yield f(a, b, c)    }    lift3(DriverManager.getConnection)(Option("127.0.0.1"), Option("sulliy"), Option("sulliy"))  }

11行-16行,示例了通过一个文件名获取File对象。由于输入参数是Option[String],该函数可以接受None,既null。map、filter、getOrElse都是Option的成员函数:

@inline final def map[B](f: A => B): Option[B] =       if (isEmpty) None else Some(f(this.get))   @inline final def filter(p: A => Boolean): Option[A] =       if (isEmpty || p(this.get)) this else None   @inline final def getOrElse[B >: A](default: => B): B =       if (isEmpty) default else this.get

前两个函数都又返回了Option[],所以我们可以进行级联的书写。map返回None(Option的子类),None的filter返回None,None的getOrElse返回default,即new java.io.File( System.getProperty("java.io.tmpdir")。

我们在需要创建一个对象或者返回一个缺省对象的时候,可以使用这种方法。

18行-21行,示例了将Option放在for循环里面。由于username1赋值了,username2为空,因此20行会被执行,24行不会被执行。37行-47行,给了一个更加复杂的例子。

49行-56行,示例了通过一个可能未初始化的对象来创建新对象。用到了yield。

58行-62行,提供了一个通用方法,将普通的Java方法封装为支持Option的新的Scala方法。这样,我们就不需要自己去处理所有参数的null检查。

多态环境下的等价判断

核心规则5:在使用多态情况下,使用scala.Equals提供的模板。

前面已经提到了scala.Equals,需要注意的是:请同时重写canEqual和equal。

关于如何理解Scala的核心规则就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

--结束END--

本文标题: 如何理解Scala的核心规则

本文链接: https://lsjlt.com/news/287850.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何理解Scala的核心规则
    这篇文章将为大家详细讲解有关如何理解Scala的核心规则,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Read Eval Print Loop (REPL)REPL在Scala里面指的是直接...
    99+
    2023-06-17
  • 如何理解Ajax核心XMLHttpRequest
    这篇文章主要讲解了“如何理解Ajax核心XMLHttpRequest”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解Ajax核心XMLHttpRequ...
    99+
    2024-04-02
  • 如何理解VB.NET继承规则
    如何理解VB.NET继承规则,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。VB.NET中也有继承相关应技术,而且相对于初学者来说并不是很好理解这一应用。下面就首先让我们从VB....
    99+
    2023-06-17
  • 如何理解Linux iptables的规则组成
    本篇内容介绍了“如何理解Linux iptables的规则组成”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!《Linux iptables:...
    99+
    2023-06-13
  • 如何理解Spark中的核心概念RDD
    如何理解Spark中的核心概念RDD,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。RDD全称叫做弹性分布式数据集(Resilient Dist...
    99+
    2024-04-02
  • 如何快速理解MySQL核心技术?
    如何快速理解MySQL核心技术?MySQL是一种常用的关系型数据库管理系统,广泛应用于各种应用程序和网站开发中。理解MySQL的核心技术对于数据库开发和管理非常关键。本文将介绍一些快速理解MySQL核心技术的方法和建议。首先,了解MySQL...
    99+
    2023-10-22
    MySQL 数据库 核心技术
  • ajax的核心怎么理解
    这篇“ajax的核心怎么理解”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“ajax的核心怎...
    99+
    2024-04-02
  • 如何理解Kubernetes核心概念与组件
    本篇内容主要讲解“如何理解Kubernetes核心概念与组件”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解Kubernetes核心概念与组件”吧!Kub...
    99+
    2024-04-02
  • Java规则引擎easy-rules如何理解
    Java规则引擎easy-rules如何理解,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。最近在思考一个基于规则进行挑选的技术重构,想通过规则引擎进行实现,借着...
    99+
    2023-06-22
  • 理解Go语言内存优化的核心原则与方法
    Go语言内存优化的核心原则是尽量减少内存的分配和释放操作,以减少垃圾回收的压力和提高程序性能。以下是一些常见的方法和技巧:1. 使用...
    99+
    2023-10-08
    Golang
  • 如何理解PHP核心特性命名空间
    目录提出定义使用限定符在内部访问命名空间转义\符号提出 PHP 在 5.3 后提出了命名空间用来解决组件之间的命名冲突问题,主要参考了文件系统的设计: 同一个目录下不允许有...
    99+
    2024-04-02
  • 如何理解Java规则引擎Apache Camel 2.9.1
    本篇文章为大家展示了如何理解Java规则引擎Apache Camel 2.9.1,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Apache Camel 2.9.1 修复了109个bug。Apache...
    99+
    2023-06-17
  • 如何理解Java Socket聊天程序核心代码
    如何理解Java Socket聊天程序核心代码,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Java Socket聊天程序在编写的时候需要我们注意很多的事情,本程...
    99+
    2023-06-17
  • PHP逻辑的核心原理解析
    PHP是一种广泛应用于网站开发的脚本语言,其逻辑处理能力是实现网站功能的关键。本文将深入探讨PHP逻辑的核心原理,包括变量、运算符、控制结构和函数等,同时提供具体的代码示例进行解析。 ...
    99+
    2024-03-06
    解析 核心原理 php逻辑
  • 理解Golang泛型的核心概念
    go 泛型允许创建可重用类型和函数,不会修改代码本身。它包括:泛型类型:使用类型参数,允许在创建类型时指定参数类型(如 []t、map[k]v)。泛型函数:使用类型参数,必须指定显式的类...
    99+
    2024-04-03
    golang 泛型
  • 如何理解CDN的核心技术之一:负载均衡
    本篇内容主要讲解“如何理解CDN的核心技术之一:负载均衡”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解CDN的核心技术之一:负载均衡”吧!CDN是近年来从美国首先兴起并迅速发展起来的一种...
    99+
    2023-06-10
  • 如何解读Java HashMap核心源码
    这期内容当中小编将会给大家带来有关如何解读Java HashMap核心源码,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。对HashMap实现的源码进行简单的分析。 所使用的HashMap源码的版本信息如下...
    99+
    2023-06-17
  • 如何理解golang里面的读写锁实现与核心原理
    如何理解golang里面的读写锁实现与核心原理,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。基础筑基读写锁的特点读写锁区别与互斥锁的主要区别就是读锁之间是共享的...
    99+
    2023-06-19
  • 如何理解SpringBoot核心运行原理和运作原理源码
    如何理解SpringBoot核心运行原理和运作原理源码,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。SpringBoot核心运行原理Spr...
    99+
    2024-04-02
  • 如何理解网站内容优化是SEO优化的核心
    这期内容当中小编将会给大家带来有关如何理解网站内容优化是SEO优化的核心,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。SEO的主要工作是通过了解各类搜索引擎如何抓取互联网...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作