我想在Scala中关注...
def save(srcPath: String, destPath: String) {
if (!destPath.endsWith('/'))
destPath += '/'
// do something
}
...但我不能认为destPath
是一个val。有没有办法将destPath
声明为var?
注意:有类似的问题,但在所有这些问题中OP只是想修改数组。
请不要告知以下内容:
变换输入参数通常被认为是糟糕的风格并且使它成为现实 更难以推理代码。
我认为它在命令式编程中是有效的(Scala允许两者,对吗?)并添加像tmpDestPath
这样的东西只会增加混乱。
void printPlusOne(int i) {
i++;
System.out.println("i is: " + i);
System.out.println("and now it's same: " + i);
}
我不必创建新变量,也不必两次计算i + 1.
答案 0 :(得分:29)
你不能。
你必须声明一个额外的var
(或使用更实用的风格: - ))。
简单示例:
def save(srcPath: String, destPath: String) {
val normalizedDestPath =
if (destPath.endsWith('/')) destPath
else destPath + '/'
// do something with normalizedDestPath
}
答案 1 :(得分:9)
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
}
然后,用户必须在途中使用。(当然,他们会被save("/here",Mut("/there"))
诱惑,这会抛弃改变,但是传递的情况总是这样。参考函数参数。)
编辑:您提出的建议是非专业程序员之间最大的混淆之一。也就是说,当您修改函数的参数时,您是修改本地副本(按值传递)还是原始(按引用传递)?如果您甚至无法修改它,很明显您所做的任何事情都是本地副本。
就这样做。
val destWithSlash = destPath + (if (!destPath.endsWith("/")) "/" else "")
值得对实际发生的事情缺乏困惑。
答案 2 :(得分:6)
也许您可以让类型系统为您完成工作,因此您甚至不必担心每次都添加斜杠:
class SlashString(s: String) {
override val toString = if (s endsWith "/") s else s + "/"
}
implicit def toSlashString(s: String) = new SlashString(s)
现在您根本不需要任何代码来更改输入String
:
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版本中的隐式类,它会更少 - 并且它会消除方法中的所有混乱,这是您所担心的。
答案 3 :(得分:1)
String对象在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
//
}
答案 4 :(得分:0)
以下是一些建议:
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))
答案 5 :(得分:0)
不,Scala不允许这样做。其他人已经描述了一些低级别的解决方法(都很好),但我会添加更高级别的解决方法。对于这种字符串规范化目的,我使用后缀,前缀,removeSuffix和removePrefix等方法保留了对scala.String的pimped扩展。后缀和前缀追加或前置一个字符串到另一个字符串,除非后缀或前缀已经存在。 removeSuffix和removePrefix做的很明显,从另一个字符串的末尾或开头删除一个字符串(如果它存在)。您的用例将被编写
val normalizedPath = destPath.addSuffix("/")
如果您进行大量的数据分析或文件操作,这些方法非常方便,您不会相信没有它们。
答案 6 :(得分:0)
我知道这是一个老问题,但如果您只是想重用参数名称:
def save(srcPath: String, destPath: String) {
((destPath: String) => {
// do something
})(if (!destPath.endsWith('/')) destPath + '/' else destPath)
}