Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
基本Scala OOP问题-按引用传递?_Oop_Scala - Fatal编程技术网

基本Scala OOP问题-按引用传递?

基本Scala OOP问题-按引用传递?,oop,scala,Oop,Scala,我有点困惑于这个问题有多么愚蠢,我有一个严重的头脑空白,但我想我还是可以问一下 我有一个对象Foo,有几个字段。我想要一个方法,它可以根据作为参数传入的字段更改任何字段。像这样: class Foo { var x = 0 var y = 0 } class Bar { def changeFooField(field : Int) = { field = 1 } } 我可以不这样使用它吗 changeFooField(foo.

我有点困惑于这个问题有多么愚蠢,我有一个严重的头脑空白,但我想我还是可以问一下

我有一个对象Foo,有几个字段。我想要一个方法,它可以根据作为参数传入的字段更改任何字段。像这样:

class Foo {
    var x = 0
    var y = 0
}

class Bar {
    def changeFooField(field : Int) = {
        field = 1        
    }
}
我可以不这样使用它吗

changeFooField(foo.x)

如果没有,我如何才能做到这一点?

不,您不能。您需要将字段值包含到对象中:

class Field[T]( var value: T )

class Foo {
  val x = new Field(0)
  val y = new Field(0)
}

class Bar {
  def changeFooField( field: Field[Int] ) {
    field.value = 1
  } 
}

val f = new Foo
(new Bar).changeFooField( f.x )
println( f.x.value + " / " + f.y.value ) // prints "1 / 0"

您想要的东西在Scala/Java中不存在。最接近的事情是传递setter函数

scala> class Foo {
     | var x = 0
     | var y = 0
     | val xSetter = (i:Int) => x = i
     | val ySetter = (i:Int) => y = i
     | }
defined class Foo

scala> def setField(setter:Int=>Unit) = setter(1)
setField: (setter: (Int) => Unit)Unit

scala> val f = new Foo
f: Foo = Foo@eb203b

scala> f.x
res0: Int = 0

scala> setField(f.xSetter)

scala> f.x
res3: Int = 1

一个常见的习惯用法是传递一个显式setter方法,该方法负责更改值

class Foo {
  var x = 0
  var y = 0
}

class Bar {
  def changeFooField(setter: (Int) => Unit) = {
    setter(1)
  }
}

val foo = new Foo
val bar = new Bar
bar.changeFooField(foo.x = _) // or equivalent: bar.changeFooField((i: Int) => foo.x = i)

assert(foo.x == 1)
(foo.x=\ucode>是一个简单的临时闭包,允许对
foo.x
进行写访问。无需将此setter API添加到
Foo
本身


因此,事实证明,setter方法(
foo.x=
–或者更确切地说,
foo.x_=
)作为参数传递,与传递任何其他方法一样。您必须记住,Scala中的
val
var
实际上并不指定变量,而是创建方法,然后使用这些方法访问真实(隐藏)变量。(
val
只创建一个getter方法,而
var
当然同时创建getter和setter)。

与上述所有答案相反,在Scala中,这实际上是完全可行的,无需编写任何特殊的包装器类

首先,您需要知道,对于任何非私有类var,例如原始问题中使用的类,Scala会自动生成getter和setter。因此,如果我们有一个名为“color”的var,Scala会自动创建一个名为“color”的getter和一个名为“color”的setter

接下来,您需要知道Scala允许您通过对任何方法调用特殊的“\u1”方法来获取对该方法的引用(这需要在其前面留出一个空格以消除歧义)

最后,将这些事实放在一起,您可以轻松获得对任何var的getter/setter的类型安全引用,并使用该引用动态设置/获取该var的值:

class Foo {
    var x = 0
}

object Foo {
    def setField[T](setter: T => Unit, value: T) {setter(value)}
    def getField[T](getter: () => T ) = {getter()}
}

val f = new Foo
val xsetter = f.x_= _
val xgetter = f.x _

Foo.setField(xsetter, 3)
println(f.x) //prints 3
println(Foo.getField(xgetter)) //prints 3

好的,谢谢。是的,我认为如果不创建一个新的对象来包装这个字段,这是不可能的。@Dominic基本的问题,没有明确提到,就是
Int
s是不可变的。如果您的字段类型是可变的,如上面的示例所示,那么很容易用+1来代替定义
设置字段
,我可以只应用
xSetter
,比如
f.xSetter(1)
。正确的?要达到同样的效果?@Nishant但是在这种情况下你也可以做
f.x=1
。@Debilski哦,对了。:)所以我不知道为什么它是间接的?我的意思是,在斯卡拉有这样的模式吗?啊,没关系。通过引用传递是OP想要解释的。它是间接完成的,因为您不能在Scala中传递
var
字段本身。因此,如果希望在其他方法中进行更改,则必须传递类本身或
var
的特定setter。