Scala语言备忘拾遗 – 1
Scala语言备忘拾遗 – 1
Scala 语法十分灵活,为了追求极致简洁,把各种符号玩的出神入化,一段时间不复习就会遗忘.
以下总结之以备忘.
1. 关于大括号(花括号)
1.1. 首先,大括号括住的是代码块
代码块有值,代码块的值是代码块中最后一个表达式的值.
println({
val x = 1 + 1
x + 1
}) // 3
1.2. call-by-name(传名调用)
传名调用用来设置函数处理传入参数时的处理方式.
正常情况下,函数F(x:Int)
接收一个Int型的参数,但在调用F时可以传入一个函数调用B(参数列表)
,只要B
的返回值是Int
即可.
于是,调用F的写法可以为F(B(参数列表))
,这里在F执行之前是需要首先计算下B(参数列表)
的返回值,然后将返回值再传递给F,不管这个返回值在F内部被使用了多少次,返回值都是固定不变的,这种方式即是传值调用(call-by-value)
.
现在将函数F的定义稍作修改,变成F(x: => Int)
,注意在参数类型Int
之前加上了 =>
表示这个函数的使用参数的方式为传名调用(call-by-name)
.
假如现在传递的参数还是一个函数调用 x=B(参数列表)
, 那么在F函数体内,每次使用x时函数调用B(参数列表)
都会被重新执行,产生最新鲜的返回值,然后再赋值给x使用.
和函数类型参数的区别
函数类型参数只是定义函数参数类型,而在函数参数类型之前加上 =>
改变的是函数参数的处理方式,两者可以说是不相干的.
假如A(f: () => Int), 则函数A接受一个函数类型参数f,这个f不接受参数,返回一个Int,但,即使f不接受参数, ()也不能省略(如果省略,就表示接受一个Int参数的传名调用方式参数了),且()表示f不能接受任何参数(区别于传名调用时的函数调用
可以是任意函数调用,只要返回值是Int).
同时,在A函数体内,f是函数引用,是可以用f()来调用的.
而F(x: => Int)
接受参数只能是Int,这个Int当然可以是其他函数调用的返回值,这个返回值不会在调用F之前计算,而是在F中用到时才(就)计算.
在F函数体内,不能进行x()这样的调用,因为x只是个Int.
再比如有M(g: (x:Int) => Int )
,这个函数M接受的是函数类型的参数g,g接受一个Int返回一个Int,并且不是传名调用,
意味着,g如果是某个函数调用的返回值,则在调用M之前先计算这函数调用,返回g,只计算一次.
更变态一点
比如有N(h: => (x:Int) => Int )
表示N接受一个函数类型的参数,函数类型签名为(x:Int) => Int ), N使用传名调用方式,意味着,如果
h是某个函数的调用,则在N函数体内每次用到h值时都会重新计算函数调用获得新的h.
一个例子, 参考了这个
package com.jack.yin.learn.concurrency.ch02
object TestCallByName {
var money = 20
val price = 1
def drink(drinkTimes:Int): Unit = {
money -= drinkTimes * price
}
def count_money_left_after_drink_by_drink_time(drinkTimes:Int): Int = {
drink(drinkTimes)
money
}
def printByName(x: => Int): Unit = {
for (i <- 0 until 5)
println(x)
}
def printByValue(x: Int): Unit = {
for (i <- 0 until 5)
println(x)
}
def main(args: Array[String]) = {
printByName(count_money_left_after_drink_by_drink_time(1))
// 传名调用,传入函数调用,可以时任意函数的调用,带的参数也就可以是任意的, count_money_left_after_drink_by_drink_time(1) 在println(x)时被计算
println("~~~~~~~~~~~~~~~~~~~~~~~")
printByName(1) // 传名调用,传入常量,相当与常量表达式每次都会被求值,结果其实不变
println("~~~~~~~~~~~~~~~~~~~~~~~")
printByValue(count_money_left_after_drink_by_drink_time(1))
// 传值调用, 传入函数调用时,先计算函数调用的返回值,count_money_left_after_drink_by_drink_time(1)只计算一次,在调用printByValue()之前计算
println("~~~~~~~~~~~~~~~~~~~~~~~")
printByValue(1) // 传值调用,传入常量,没啥特别的
}
}
赞 赏 微信赞赏
支付宝赞赏
本文固定链接: https://www.jack-yin.com/coding/essay/3150.html | 边城网事