作者:zhaobo | 来源:互联网 | 2023-02-11 14:09
所以我正在学习Scala,我遇到了这个挑剔的问题......
如果我们有一个String
并希望将其转换成一个Int
,我在网上找到的所有例子都说:"这很简单!只需使用String.toInt
!"
好的:
var x = readLine().toInt
很简单.我假设toInt
是一个功能String
.但如果是这样的话,我应该可以toInt
用括号打电话,对吧?来自Java,这对我来说更自然:
var x = readLine().toInt()
可惜!Scala给了我以下错误:
[错误] /home/myhome/code/whatever/hello.scala:13:Int不带参数
[error] var x = readLine().toInt()
好奇.这个错误是什么意思?是toInt
不是一个功能String
?同样,为什么我可以两个都做:
var x = readLine().toLowerCase()
var y = readLine().toLowerCase
没有任何问题?
编辑:重复的问题不解决toLowerCase
vs toInt
问题.
1> Travis Brown..:
这是一个很好的问题,我不认为它是关于定义带或不带括号的零度方法的问题的重复.
这里toInt
和之间的区别在于toLowerCase
它toInt
是标准库StringOps
类提供的语法丰富.您可以使用reify
和showCode
在REPL中检查:
scala> import scala.reflect.runtime.universe.{ reify, showCode }
import scala.reflect.runtime.universe.{reify, showCode}
scala> showCode(reify("1".toInt).tree)
res0: String = Predef.augmentString("1").toInt
这只是去除了浓缩方法调用,并向您显示已应用隐式转换来支持它.
如果我们查看toInt
方法StringOps
,我们会看到它的定义没有括号.正如可能重复问题的答案所指出的那样,如果Scala中的零arity方法定义为没有括号,则不能用括号调用它(尽管如果它用括号定义,它可以以任一方式调用).
所以这就是为什么"1".toInt()
不起作用.如果String
是遵循正常Scala命名约定的普通Scala类,"ABC".toLowerCase()
也不会工作,因为该方法将被定义为没有括号,因为它不是副作用(这只是一个约定,但它往往在Scala中非常一致地应用)码).
问题是,String
它实际上并不是Scala标准库中的一个类 - 它只是java.lang.String
.在JVM级别,使用括号定义的零arity方法和没有括号定义的零arity方法之间没有区别 - 这纯粹是Scala的区别,并且它不是在JVM方法签名中编码,而是在一个单独的一批元数据中存储在类文件.
Scala语言设计者决定将所有未在Scala中定义的零方法(因此没有这些额外的元数据)视为用括号定义.由于toLowerCase
方法on String
真的是一个java.lang.String
类的方法(不是类似的语法丰富方法toInt
),它属于这个类,这意味着你可以用任何一种方式调用它.
我会稍微谈谈Travis如何解释"副作用",因为它非常重要,对于来自Java背景的人来说,它可能并不那么明显.如果函数以任何方式执行某些影响函数体外"世界状态"的操作,则函数是副作用的.这并不意味着它必须改变一些价值观; 足以让它的效果可观察到(例如印刷到控制台,正如Travis所说).这是不好的.函数的另一个坏处是保持一些可变状态,这可能导致为相同的输入参数返回不同的结果.
如果一个函数没有副作用,只取决于它的参数并且总是为相同的参数返回相同的结果,我们称这样的函数为"纯".对于零参数函数,我们失去了仅依赖于其参数并且对于相同参数总是返回相同结果的条件(因为没有参数)所以我们所有可能"搞乱"的是具有副作用.如果我们没有(没有打印,没有记录,没有任何请求,没有数据库写入等),那么它是一个安全的,幂等函数 - 一个简单的getter,如果你愿意的话 - 按照惯例,它应该没有括号.