zoukankan      html  css  js  c++  java
  • Scala 基础(5)—— 构建函数式对象

    有了 Scala 基础(4)—— 类和对象 的前提,现在就可以来构建一个基于 Scala 的函数式对象。

    下面开始构造一个有理数对象 Rational。

    1. 主构造方法和辅助构造方法

    对于每一个类的定义,Scala 只允许一个主构造方法,主构造方法的入参紧跟在类定义的后面:

    class Rational(n: Int, d: Int) {
    
    }
    
    val r = new Rational(1,2) // 有理数 1/2
    

    你可能需要一个分母 d 被预定义为 1 的一个构造方法,这事就需要用到辅助构造方法(auxiliary constructor)。

    辅助构造方法以 def this(...) 开始:

    class Rational(n: Int, d: Int) {
    
      def this(n: Int) = this(n, 1)
    }
    
    val r = new Rational(5) // 有理数5
    

    2. 前置条件

    你可能需要对初始化一个对象进行一些参数检查,例如有理数的分母 d 不能为 0。

    在每一个 Scala 文件中都会自动引用 Predef 这个独立对象,里面有 require() 方法能够满足这个需求。

    class Rational(n: Int, d: Int) {
      require(d != 0)
    
    def this(n: Int) = this(n, 1) } val r = new Rational(5, 0) // 会抛出异常

    3. toString() 方法

    对于一个类来说,重写 toString() 方法是一个很常见的需求。

    需要注意的是 Scala 对于重写父类方法,会强制加上 override,而在 Java 中这一行为是 optional 的。

    class Rational(n: Int, d: Int) {
      require(d != 0)
    
    def this(n: Int) = this(n, 1)
    override def toString: String = n + "/" + d // 去掉 override 会编译报错 }

    4. 添加字段和方法

    在这里为 Rational 类添加一个 add() 方法,这里会出现一个初学者常见的错误:

    class Rational(n: Int, d: Int) {
      require(d != 0)
    
      def this(n: Int) = this(n, 1)
    
      override def toString: String = n + "/" + d
    
      def add(that: Rational): Rational = new Rational(n * that.d + that.n * d, d * that.d)
    }

    这段逻辑看似没有问题,而且编译期间也不会报错,但是运行时却会报错。

    原因在于,虽然当前对象 this 可以很自然地使用构造方法传入的 n 和 d,但是 that 对象却不能这么使用。

    这时就要增加字段:

    class Rational(n: Int, d: Int) {
      require(d != 0)
    
      val numer: Int = n
      val denom: Int = d
    
      def this(n: Int) = this(n, 1)
    
      override def toString: String = n + "/" + d
    
      def add(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom)
    }
    

    对于有理数来说,我们不希望出现 2/10 这样的数字,而是 1/5,这时就要增加私有的方法 gcd 来求最大公约数,以及私有字段 g 存储最大公约数:

    class Rational(n: Int, d: Int) {
      require(d != 0)
    
      private val g = gcd(n.abs, d.abs)
      val numer: Int = n / g
      val denom: Int = d / g
    
      def this(n: Int) = this(n, 1)
    
      override def toString: String = numer + "/" + denom
    
      def add(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom)
    
      private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
    }
    

     

    5. 定义操作符

    Scala 可以用定义方法同样的方式定义操作符,达到类似“操作符重载”的效果。

    例如,add 方法可以用 + 操作符代替:

    class Rational(n: Int, d: Int) {
      require(d != 0)
    
      private val g = gcd(n.abs, d.abs)
      val numer: Int = n / g
      val denom: Int = d / g
    
      def this(n: Int) = this(n, 1)
    
      override def toString: String = numer + "/" + denom
    
      def +(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom)
    
      private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
    }
    
    val r1 = new Rational(5, 10)
    val r2 = new Rational(3, 10)
    println(r1 + r2) // 可以用+操作符,结果是 4/5
    

    由此处可见,Scala 中的标识符分为2种:

    • 字母数字组合标识符:规则基本与 Java 相同,推荐驼峰命名法。
    • 操作标识符:由一个或多个操作字符构成。

    6. 方法重载

    与 Java 相同,Scala 支持相同方法名,不同的参数列表的方法重载:

    class Rational(n: Int, d: Int) {
      require(d != 0)
    
      private val g = gcd(n.abs, d.abs)
      val numer: Int = n / g
      val denom: Int = d / g
    
      def this(n: Int) = this(n, 1)
    
      override def toString: String = numer + "/" + denom
    
      def +(that: Rational): Rational = new Rational(numer * that.denom + that.numer * denom, denom * that.denom)
    
      def +(that: Int): Rational = new Rational(numer + that * denom, denom)
    
      private def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b)
    }
    
  • 相关阅读:
    c语言中srand和rand函数 生成随机数总结
    枚举类型
    VS2008快捷键使用技巧
    PV实现同步
    PV操作(深入显出)
    数字在排序数组中出现的次数
    两个链表的第一个公共结点
    数组中的逆序对
    第一个只出现一次的字符位置
    丑数
  • 原文地址:https://www.cnblogs.com/jing-an-feng-shao/p/10269822.html
Copyright © 2011-2022 走看看