返回介绍

数学基础

统计学习

深度学习

工具

Scala

七、可变对象

发布于 2023-07-17 23:38:23 字数 6324 浏览 0 评论 0 收藏 0

  1. Scala 中可以定义带有可变状态的对象。当我们希望对真实世界中那些随着时间变化的对象进行建模时,自然而然就会想到这样的可变对象。

  2. 不可变对象的一个特点是:当多次调用某个不可变对象的方法或者获取其字段时,总能得到相同的结果。如:

    
    
    xxxxxxxxxx
    val list = List('a','b','c')

    list.head 的调用总是会返回'a' ,无论调用多少次、无论调用前后执行了什么其它操作。

  3. 可变对象的一个特点是:方法调用或者字段访问的结果可能取决于该对象被执行了哪些操作。

    
    
    xxxxxxxxxx
    class C { private var num: Int = 0 def currentNum: Int = num def addN(n: Int) = { require(n>0) num += n } def subN(n: Int): Boolean = { if(n>num) false else: { num -= n true } } } val c = new C

    c.currentNum 的同样的、多次调用结果可能会不同,这取决于调用前后是否执行了 c.addNc.subN 操作。

  4. 对象的可变和 var 通常成对出现,但是有时候不是那么清晰。

    • 一个类可能并没有定义或者继承任何var 变量,但是它依然是可变的。因为该类将方法调用转发到其它带有可变状态的对象上。

    • 一个类可能包含了 var ,但是它依然是纯函数式的。如:

      
      
      xxxxxxxxxx
      class Key { def computeKey: Int = .... // 计算 key,这需要时间 } class CachedKey extends Key { private var keyCache: Option[Int] = None def computeKey: Int = { if (!keyCache.isDefined) keyCache = Some(super.computeKey) // 写缓存 keyCache.get // 从缓存中读取 } }

      通过使用 CachedKey,可以加速computeKey 。除了速度上的提升,Key 类和 CachedKey 类的行为完全一致。如果说Key 类是纯函数式的,那么CachedKey 也是纯函数式的,即使它包含一个var 变量。

  5. 对一个可被重新赋值的变量,我们可以做两种基本操作:获取它的值,修改它的值。

    • 在诸如JavaBeans 的类库中,这些操作通常被包装成单独的 gettersetter 方法,我们需要显式的定义这些方法。

    • Scala 中,每个非私有的var 成员都隐式定义了对应的 gettersetter 方法。不过这些 getter 方法和 setter 方法的命名和 Java 的习惯不一样,对于 var x

      • getter 方法的名字为 x
      • setter 方法的名字为 x_=
      
      
      xxxxxxxxxx
      class C{ var name:String = "hello" } val c = new C println("get name:"+c.name) // 输出: get name:hello c.name = "world" println("after setter: get name:"+c.name)// 输出: after setter: get name:world

      这里除了定义一个可被重新赋值的字段外,编译器还将生成一个名为 namegetter 和一个名为 name_=setter

      • 其中的字段总是被标记为 private[this] ,这意味着该字段只能从包含它的对象中访问。

      • gettersetter 拥有跟原来的 var 相同的可见性。

        • 如果原来的 var 定义是公有的,则它的 gettersetter 也是公有的。
        • 如果原来的 var 定义是 protected 的,则它的 gettersetter 也是 protected 的。

      因此上例中的代码等效于:

      
      
      xxxxxxxxxx
      class C{ private[this] var n = "hello" def name: String = n def name_=(x:String) = { n = x } }
  6. var 展开成gettersetter 的机制的一个有趣点是:你可以逆向使用该机制,人工订制 getter 方法和 setter 方法。

    
    
    xxxxxxxxxx
    class C{ private[this] var n:Int = 0 def age: Int = n def age_=(num:Int) = { require(0<= num && num<=120) n = num } } ​ val c = new C println("get age:"+c.age) // 输出: get age:0 c.age = 20 println("after setter: get age:"+c.age) // 输出: after setter: get age:20 c.age = -1 // 异常

    其优点是:你可以在人工定制的 setter 方法里增加一些特殊的配置,如:增加参数限制、记录此次修改、发送通知、触发事件等。

    其它语言有些特殊的语法来表示,如python 语言的 property 语法。

  7. Scala 允许我们定义不跟任何字段关联的 gettersetter

    距离可以用千米来表示,因此我们内部存储的单位是,但是gettersetter 操作的是千米

    
    
    xxxxxxxxxx
    class Distance{ private[this] var m:Double = 0 // 单位: 米 def km: Double = m/1000 // getter: 单位: 千米 def km_=(num:Double) = { m = num*1000 } // setter: 单位: 千米 } ​ val d = new Distance println("get km:"+d.km) // 输出: get km:0.0 d.km = 10 println("after setter: get km:"+ d.km) // 输出: after setter: get km:10.0

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文