Scala Cookbook读书笔记 Chapter 5.Methods 第一部分

5.0 本章概述

  • Java和Scala定义简单method区别:

    // java
    public String doSomething(int x) {
        // code here
    }
    
    // scala
    def doSomething(x: Int): String = {
        // code here
    }
    
  • Scala还可以使用下面方式,不指定返回值类型,不要求包裹body的大括号:

    def plusOne(i: Int) = i + 1
    
  • 除了上面例子的区别,Java和Scala还包括以下不同:
    • 指定方法获取控制(显示)
    • 给方法参数设置默认值的能力
    • 调用方法时指定方法参数名字的能力
    • 如何声明一个方法可能抛出的异常
    • 方法里使用可变参数

5.1 控制方法范围

  • 问题:Scala方法默认是公开的,想要如Java一样控制它的范围

    5.1.1 解决方案

  • Scala从“更加限制”到“更加公开”有以下几个范围选项:

    • Object-private scope
    • Private
    • Package
    • Package-specific
    • Public

      5.1.2 Object-private scope

  • 只有当前对象的当前实例可以获取这个方法,同一个类的其他实例不可以。
  • 使用private[this]修饰符:

    private[this] def isFoo = true
    
  • 下面例子,方法doFoo使用了一个Foo对象的实例,但是isFoo方法声明成Object-private,因为当前Foo实例不能获取到其他实例的isFoo方法,所以下面代码不会编译:

    class Foo {
    
        private[this] def isFoo = true
    
        def doFoo(other: Foo) {
            if (other.isFoo) { // this line won't compile
                // ...
            }
        }
    }
    

    5.1.3 Private scope

  • 存在于当前类和当前类的其他实例,和Java中使用private一样,把上面的private[this] 改为private就可以编译成功了:

    class Foo {
    
        private def isFoo = true
    
        def doFoo(other: Foo) {
            if (other.isFoo) { // this now compiles
                // ...
            }
        }
    }
    
  • private方法,子类不可以获取:

    class Animal {
        private def heartBeat {}
    }
    
    class Dog extends Animal {
        heartBeat // won't compile
    }
    

    5.1.4 Protected scope

  • Protected方法子类可获取

    class Animal {
        protected def breathe {}
    }
    
    class Dog extends Animal {
        breathe
    }
    
  • Java中protected方法可以被同一个包的其他类获取,Scala不是这样,下面不会编译:

    package world {
    
        class Animal {
            protected def breathe {}
        }
    
        class Jungle {
            val a = new Animal
            a.breathe // error: this line won't compile
        }
    }
    

5.1.5 Package scope

  • 当前包内所有成员可见,使用private[packageName]表示对当前包私有,下面doX可以被同一个包内所有类获取,doY只能被Foo类获取:

    package com.acme.coolapp.model {
    
        class Foo {
            private[model] def doX {}
            private def doY {}
        }
    
        class Bar {
            val f = new Foo
            f.doX // compiles
            f.doY // won't compile
        }
    }
    

    5.1.6 更多package等级控制

  • 不同包等级权限不同

    package com.acme.coolapp.model {
        class Foo {
            private[model] def doX {}
            private[coolapp] def doY {}
            private[acme] def doZ {}
        }
    }
    
    import com.acme.coolapp.model._
    
    package com.acme.coolapp.view {
        class Bar {
            val f = new Foo
            f.doX // won't compile
            f.doY
            f.doZ
        }
    }
    
    package com.acme.common {
        class Bar {
            val f = new Foo
            f.doX // won't compile
            f.doY // won't compile
            f.doZ
        }
    }
    

    5.1.7 Public scope

  • 不添加任何权限修饰符,方法是公开的:

    package com.acme.coolapp.model {
        class Foo {
            def doX {}
        }
    }
    
    package org.xyz.bar {
        class Bar {
            val f = new com.acme.coolapp.model.Foo
            f.doX
        }
    }
    

5.1.8 讨论

Table 5-1. Descriptions of Scala’s access control modifiers

Access modifier Description
private[this] The method is available only to the current instance of the class it’s declared in.
private The method is available to the current instance and other instances of the class it’s declared in.
protected The method is available only to instances of the current class and subclasses of the current class.
private[model] The method is available to all classes beneath the com.acme.coolapp.model package.
private[coolapp] The method is available to all classes beneath the com.acme.coolapp package.
private[acme] The method is available to all classes beneath the com.acme package.
(no modifier) The method is public.