Scala-可变(var)方法参数引用
编辑:我一直在这里获得选票。为了记录在案,我不再认为这很重要。自从我把它贴出来后,我就不需要它了 我想做以下在ScalaScala-可变(var)方法参数引用,scala,variables,methods,parameters,Scala,Variables,Methods,Parameters,编辑:我一直在这里获得选票。为了记录在案,我不再认为这很重要。自从我把它贴出来后,我就不需要它了 我想做以下在Scala def save(srcPath: String, destPath: String) { if (!destPath.endsWith('/')) destPath += '/' // do something } 。。。但是我不能因为destPath是val。有没有办法将destPath声明为var 注意:有类似的问题,但在所有这些问题中
def save(srcPath: String, destPath: String) {
if (!destPath.endsWith('/'))
destPath += '/'
// do something
}
。。。但是我不能因为destPath
是val。有没有办法将destPath
声明为var
注意:有类似的问题,但在所有这些问题中,OP只是想修改数组
请不要建议以下事项:
改变输入参数通常被视为不好的风格,并使其
关于代码更难推理
我认为它在命令式编程中是有效的(Scala允许两者,对吗?),添加类似tmpDestPath
的东西只会增加混乱
编辑:不要误解。我知道字符串是不可变的,我不想引用引用,因为我不想修改调用方的数据。我只想修改调用方给我的字符串的本地引用(例如orig+'/')。我只想在当前方法的范围内修改该值。看,这在Java中非常有效:
void printPlusOne(int i) {
i++;
System.out.println("i is: " + i);
System.out.println("and now it's same: " + i);
}
我不必创建新变量,也不必计算两次I+1。JVM不允许通过引用传递指向对象的指针(在C++中就是这样做的),因此您不能完全按照自己的意愿执行操作 一个选项是返回新值:
def save(srcPath: String, destPath: String): String = {
val newPath = (if (!destPath.endsWith("/")) destPath+'/' else destPath)
// do something
newPath
}
另一种方法是创建包装器:
case class Mut[A](var value: A) {}
def save(srcPath: String, destPath: Mut[String]) {
if (!destPath.value.endsWith("/")) destPath.value += '/'
// do something
}
哪些用户在进入时必须使用。(当然,他们会尝试保存(“/here”,Mut(“/there”)
,这将丢弃更改,但对于传递引用函数参数,情况总是如此。)
编辑:你的建议是非专家程序员最大的困惑之一。也就是说,修改函数的参数时,是修改本地副本(按值传递)还是原始副本(按引用传递)?如果您甚至不能修改它,那么很明显,您所做的任何事情都是本地副本 就这样做吧
val destWithSlash = destPath + (if (!destPath.endsWith("/")) "/" else "")
不必对实际发生的事情感到困惑,这是值得的。字符串对象在Scala(和Java)中是不可变的。我能想到的备选方案是:
def save(srcPath: String, destPath: StringBuilder) {
if (!destPath.toString().endsWith("/"))
destPath.append("/")
// do something
//
}
编辑
如果我理解正确,您希望将参数用作局部变量。不能,因为所有方法参数都是Scala中的val。
唯一要做的是首先将其复制到局部变量:
def save(srcPath: String, destPath: String) {
var destP = destPath
if (!destP.endsWith("/"))
destP += "/"
// do something
//
}
你不能
您必须声明一个额外的var
(或者使用更具功能性的样式:-)
简单的例子:
def save(srcPath: String, destPath: String) {
val normalizedDestPath =
if (destPath.endsWith('/')) destPath
else destPath + '/'
// do something with normalizedDestPath
}
以下是一些建议: 1) 稍微更新一下你的函数
def save(srcPath: String, destPath: String) {
var dp = destPath
if (!dp.endsWith('/'))
dp+= '/'
// do something, but with dp instead of destPath
}
2) 在调用save之前创建要使用的实用程序函数
def savedPath(path: String) =
if(path.endsWith("/"))
path
else
path + "/"
//call your save method on some path
val myDestPath = ...
val srcPath = ...
save(srcPath, savedPath(myDestPath))
不,这在Scala是不允许的。其他人描述了一些低级别的变通方法(都很好),但我将添加一个更高级别的变通方法。出于这种字符串规范化的目的,我保留了scala.string的一个pimped扩展,并使用了suffix、prefix、removeSuffix和removeSuffix等方法。后缀和前缀将一个字符串附加或前置到另一个字符串上,除非后缀或前缀已经存在。removeSuffix和removePrefix做的很明显,就是从另一个字符串的末尾或开头删除一个字符串(如果有)。您的用例将被编写出来
val normalizedPath = destPath.addSuffix("/")
如果你做了大量的数据分析或文件操作,这些方法非常方便,你不会相信没有它们你也能做到。也许你可以让类型系统为你做这项工作,因此你甚至不必担心每次都添加斜杠:
class SlashString(s: String) {
override val toString = if (s endsWith "/") s else s + "/"
}
implicit def toSlashString(s: String) = new SlashString(s)
现在,您根本不需要任何代码来更改输入字符串
:
def save(srcPath: String, destPath: SlashString) {
printf("saving from %s to %s", srcPath, destPath)
}
val src: String = "abc"
val dst: String = "xyz"
scala> save(src, dst)
saving from abc to xyz/
诚然,在开始时有一些设置,但在2.10版的隐式类中情况就不太一样了,而且它消除了方法中的所有混乱,这正是您所担心的。我知道这是一个老问题,但是如果您只想重用参数名称,也许:
def save(srcPath: String, destPath: String) {
((destPath: String) => {
// do something
})(if (!destPath.endsWith('/')) destPath + '/' else destPath)
}
你好非常感谢。恐怕你误解了我的问题。我已经更新了它。“JVM不允许通过引用传递指向对象的指针”,这一点需要非常仔细的澄清。在Java中传递原语时:我们实际上是在传递值。但是,当传递一个对象时:您实际上是在传递一个对该对象的引用(我们可以声称这也是通过值实现的)。出于这个原因,“Java只通过值传递”语句实际上会引起很多混乱,但实际上该断言需要理解原语是通过值传递的,对象引用是通过值传递的。Hello。非常感谢。恐怕你误解了我的问题。我已经更新了。广告2。没有选择,那只是杂乱无章。StringBuilder暗示我将构建一些大字符串。如果我能做“字符串(->可能是新字符串)”,为什么要做“字符串->字符串生成器->字符串”?您的解决方案只是解决缺乏Scala知识或Scala局限性的一个解决方案。在Java中不会这样做,是吗?我并没有说使用StringBuilder很优雅,但是如果您不想将字符串作为返回值返回,那么您必须使用某种可变字符串类型的参数。实际上,您可以在Scala中的StringBuilder上直接使用endsWith()(您不需要调用toString())。关于最初的问题:Scala鼓励函数式编程,所以即使使用普通的变量(局部变量),也应该尽可能避免。@woky:来自Odersky(Scala的发明者)等:Scala中的编程,第二版,第52页:“Scala允许您以命令式风格编程,但鼓励您采用更具功能性的风格”以及后来的“Scala鼓励您倾向于VAL,但最终获得手头工作所需的最佳工具”。因此,根据其发明者的说法,Scala确实鼓励您进行功能性编程,