0504.操作方法(Methods)

Methods

在 Scala 中, 不存在像 Java 單純運算符的設計, 取而代之的是運算符方法(函數), 進而達到能俱 運算符 Overloading 的特性, 一切的「操作」都是函數的調用呼叫. - WisdomFish.ORG

方法定義的語法似乎比較有趣,當它使用 = 操作符時,就像將隨後的方法體賦值給 main 標識符。事實上,真正發生的事情是:
在函數語言中,就像變數和常數一樣,函數是一級概念,所以語法上也是一樣地處理。




保留字: def


在 Scala 定義一個方法以 def 為開始, ex:

def fish ...


name: type



def fish: Int

方法若不需傳遞參數, 則可省略( )

def fish = 2
public Integer fish( ) { return 2 } // Java style





可變長度引數(Varargs)方法


可變長 argument 被視為 Seq[_] 

scala> def fish(a: Int*) = a.foreach( print )
scala> def fish(a: Int*) = a.foreach( print _ )
scala> def fish(a: Int*) = a.foreach( print(_) )
fish: (a: Int*)Unit

scala> val list = 1::2::3::4::5::Nil 
list: List[Int] = List(1, 2, 3, 4, 5)

scala> fish(list: _*) 
12345

深入參考:http://daily-scala.blogspot.com/search/label/varargs



預設參數與指參[v2.8]


default parameter [2.8]

def sum(n:Int, total:Int=0):Int = if(n==0) total else sum(n-1, n+total)


named parameter [2.8]
def foo(widht:Int, height:Int) = { ... } ; foo(height=100, width=200)


scala> def fish(a: Int = 10, b: Int) { print (a + b) }
fish: (a: Int,b: Int)Unit

scala> fish(b = 10)
20



arguments:The things you specify between the parentheses when you’re invoking a method:
doStuff(“a”, 2); // invoking doStuff, so a & 2 are arguments
parameters: The things in the method’s signature that indicate what the method must receive when it’s invoked:
void doStuff(String s, int a) { } // we’re expecting two
// parameters: String and int


http://blog.csdn.net/netHibernate/archive/2010/08/11/5805461.aspx






不回傳值方法(Unit)


等價於 Java 對 void 的宣告,

語法形態
  • def 方法名稱( ) = 程序內容
  • def 方法名稱( ) { ... }

Ex.
scala> def fish( ) = println("Fish, Kuo")
fish: ( )Unit

空白的回應括號說明函數不帶參數。Unit 是 fish 的結果類型。Unit 的結果類型指的是函數沒有返回有用的值。Scala的Unit類型比較接近 Java 的 void 類型,而且實際上 Java 裡每一個返回 void 的方法都被映射為 Scala 裡返回 Unit 的方法。因此結果類型為 Unit 的方法,僅僅是為了它們的副作用而運行。

// Type Inference
scala> def fish = println("Fish, Kuo") 
fish: Unit




延伸閱讀, 0604.scala.Unit




回傳值方法與類型推演


Scala 對方法也會嘗試推斷返回值的類型, 但
  1. 帶參數的方法必須明確宣告其類型
  2. 結果類型(Result type)的宣告適用 Type inference, 
    1. 但必隨補一個等號 =; 不加等號者以不回傳值 Unit (void)論.
    2. 在函數體前觀點, 等號提示函數是定能產生一個值的表達式.
    3. 函數若是遞迴的話, 則必要顯式定義 Result type.
  3. { } 大括號的存在是可選的, 但表達式必在一行內完成.
儘管如此,就算編譯器不需要,顯式說明函數結果類型也經常是個好主意,這種類型標註可以使代碼便於閱讀,因為讀者不用研究了函數體之後再去猜結果類型。或者多以附加 = 方式, 讓 Scala 的 type inference 來主動協助我們進行初級的編譯檢查.

Ex.

scala> def mac(x: Int, y: Int) = {
     | if (x > y) x
     | else
     | y
     | }
mac: (x: Int,y: Int)Int

scala> mac(8, 5)
res2: Int = 8

scala> def mac(x: Int, y: Int): Int = {
     | if (x > y) x                  
     | else                          
     | y                             
     | }                             
mac: (x: Int,y: Int)Int

scala> mac(8, 5)                     
res4: Int = 8

scala> def mac(x: Int, y: Int) { 
     | if (x > y) x            
     | else                    
     | y                       
     | }                       
mac: (x: Int,y: Int)Unit

scala> mac(8, 5)               

scala> def mac(x: Int, y: Int):Int = if(x > y) x else y
mac: (x: Int,y: Int)Int

scala> mac(8, 5)                                      
res5: Int = 8


scala> def method1() { 6 }
method1: ()Unit

scala> def method2() = { 6 }
method2: ()Int

scala> def method3() = 6
method3: ()Int

scala> def method4 : Double = 6
method4: Double


scala> def fish(x: Int) { 6 }
fish: (x: Int)Unit

scala> def fish(x: Int) = 6
fish: (x: Int)Int

scala> def fish(x: Int) = { 6 }
fish: (x: Int)Int

scala> def fish(x: Int): Double = { 6 }
fish: (x: Int)Double





方法的調用呼叫


當調用方法如果僅有0..1個參數, 則 . 與 ( ) 是可以被忽略的, 來消減程式碼中的混亂.
  • 更富口語化更自然的表達呈現
    • 1.+(1)
      • 1 + 1
    • kiss fish 2
      • kiss.fish(2)
scala> (1 to 10) foreach(i => print(i))
12345678910





Now that you've worked with Scala variables, you'll probably want to write some methods. Here's how you do that in Scala:


Method definitions start with def instead of val or var. The method's name, in this case max, is followed by a list of parameters in parentheses. A type annotation must follow every method parameter, preceded by a colon in the Scala way, because the Scala compiler (and interpreter, but from now on we'll just say compiler) does not infer method parameter types. In this example, the method named max takes two parameters, x and y, both of type Int. After the close parenthesis of max's parameter list you'll find another 「: Int」 type specifier. This one defines the result type of the max method itself.

Sometimes the Scala compiler will require you to specify the result type of a method. If the method is recursive1, for example, you must explicitly specify the method result type. In the case of max however, you may leave the result type specifier off and the compiler will infer it. Thus, the max method could have been written:

scala> def max2(x: Int, y: Int) = if (x < y) y else x
max2: (Int,Int)Int

Note that you must always explicitly specify a method's parameter types regardless of whether you explicitly specify its result type.

The name, parameters list, and result type, if specified, form a method's signature. After the method's signature you must put an equals sign and then the body of the method. Since max's body consists of just one statement, you need not place it inside curly braces, but you can if you want. So you could also have written:

scala> def max3(x: Int, y: Int) = { if (x < y) y else x }
max3: (Int,Int)Int

If you want to put more than one statement in the body of a method, you must enclose them inside curly braces.

Once you have defined a method, you can call it by name, as in:

scala> max(3, 5)
unnamed6: Int = 5

Note that if a method takes no parameters, as in:

scala> def greet() = println("Hello, world!")
greet: ()Unit

You can call it with or without parentheses:

scala> greet()
Hello, world!
unnamed7: Unit = ()

scala> greet
Hello, world!
unnamed8: Unit = ()

The recommended style guideline for such method invocations is that if the method may have side effects4, you should provide the parentheses even if the compiler doesn't require them. Thus in this case, since the greet method prints to the standard output, it has side effects and you should invoke it with parentheses to alert programmers looking at the code.


Comments