Scala类是否有像Python一样的“self”?

4
例如,如果我有以下代码:
object Solution {
    class myClass(A: Array[Int]){
        val something: Int = A.length;
        val another: Int = something/2;
        val someName = "blah"
 ...
 ...

这些变量只存在于myClass特定的实例中,还是属于整个类共享的变量?如果是后者,我该如何使这些变量仅限于对象内部?
这些变量仅存在于myClass特定实例中,而不是在整个类中共享。如果想将这些变量限制在对象内部,可以将它们声明为私有变量。

2
有趣的是,当我在谷歌中输入您的标题时,我发现了这个链接:http://bugra.github.io/work/notes/2014-10-18/scala-basics-for-python-developers/ - kylieCatt
1个回答

6
是的,它被实现为this,就像在Java或C++中一样。您无需在方法调用时显式传递它,就像在Python中一样。
然后,在您的示例中创建的是实例变量,也称为成员变量。它们属于类的实例,即它们不是在所有相同类的对象上共享的(类变量)。对于后者,您可能需要使用配套方案
最后,您可能需要阅读一些关于Scala的内容,例如这里的教程,或者由@IanAuld提供的针对Python开发人员的教程,或者参加由Scala的创建者提供的coursera上的Scala课程
顺便说一句,欢迎来到Stack Overflow!

编辑:

所以在Scala中,我将它设置为实例变量,而如果我在Python中采用相同的方法(就位置而言),它们将成为类变量?或者您是说我必须在某个地方添加“this”才能使它们成为实例变量?

我看到了你的困惑。Python和Scala在面向对象编程方面的方法非常不同。首先让我们谈一下Python:

Python

Python的设计理念是类(以及模块)是dict,在早期版本的Python中,甚至可以通过myclass.__dict__成员访问类的成员,即使今天,即使该字典由于实现而“隐藏”,仍然可以通过getattrsetattr访问。

这个想法对于Python如何处理类非常重要,因为所有操作都是通过monkey patching完成的,即在运行时更改和实际定义类定义。

class Foo:
    pass
foo = Foo()
foo.bar = 1
print(foo.bar)

在Python中,另一个基本的特点是一切都是显式的。这就是为什么当您声明一个方法时,需要将当前类的引用作为参数明确传递给该方法的原因:

class Foo:
    def foobar(self):
        self.bar = 1
print(foo.bar)

但实际上这等同于执行:

class Foo:
    pass
def foobar(self):
    self.bar = 1
foo = Foo()
foobar(foo)
print(foo.bar)

以下行为很好地说明了什么是猴子补丁:
class Foo:
    def foobar(self):
        print(self.bar)
foo = Foo()
foo.bar = 1
foo.foobar() # prints 1

当你在Python中定义成员时,实际上你所做的是用新成员对当前实例进行monkey patching。

现在,当你使用类实例时,实际上你所做的是按照我之前告诉你的dict表示方式来操作:

Foo = dict(a=1, b=[2]) # class definition with class variables
foo = Foo.copy()       # create instance
foo['b'].append(3)     # use a class variable's instance
print(Foo['b']) # prints: [2,3]

总之,Python对于面向对象编程有一种非常特殊的方法,完全基于类似字典的想法,并且它们应该被猴子补丁定义(这就是为什么当你创建一个类时,约定是在构造函数中声明所有成员)。这些都是Python不被认为是“纯”面向对象语言的原因(这只是语言的属性,而不是资格)。
Scala
Scala被定义为一种“纯函数式和纯面向对象”的语言。这两个属性使得它与Python非常不同。我不会详细解释函数式编程,但我强烈建议您参加一门课程并阅读相关书籍来掌握它以及Scala。
因此,在Scala中,当您定义一个类时,可以执行以下操作(示例由我链接的教程提供):
class Square {
    var x: Double = 0
    var y: Double = 0
    var width: Double = 0
    var height: Double = 0
    def area(): Double = width * height
}

在这里,您定义了实例变量并为它们提供“默认”值,这就是您在Python中在__init__()构造函数中定义的内容。然后您定义一个方法。
但是,由于Scala是一种函数式语言,因此您可以对类定义进行另一种解读:
class Square(
    private var x: Double,
    private var y: Double,
    private var width: Double,
    private var height: Double
  ) {
    def area(): Double = width * height
  }

Square是一个函数,它接受参数并返回一个实例,该实例具有在该函数范围内定义的方法。因此,外部的“function”实际上是一个构造函数,而内部函数则是方法。

现在,在scala中没有实际存在的类变量,如果要这样做,您可能更喜欢使用伴侣设计模式(请参见有关它的SO答案链接)。

但是,偶然地,由于您在示例中使用的someName变量的属性:

class myClass(A: Array[Int]){
    val something: Int = A.length;
    val another: Int = something/2;
    val someName = "blah"

你的someName变量是不可变的。这意味着你不能在实例中修改它,因此对于所有实例来说它都是相同的。所以从某种程度上看,它看起来像是类变量,尽管它并不是,它们真正是实例变量。
就像我在Python中的字典示例一样,这并不完全准确,因为关于这些机制还有很多要了解——我甚至没有触及表面,但这对于展示Scala(一种函数/对象语言)和Python(一种补丁/对象语言)之间巨大的差异的目的而言是有效的。
现在从过程式编程语言转向函数式编程语言是一个相当大的步骤,感觉就像重新学习开发一样,但这绝对是值得的,因为它将教会你以不同的方式思考你的程序,不仅可以学习一门新语言和一种新范式,而且还可以通过拥有更好的实践经验和更加关注类型来提高你已经掌握的语言的开发水平。

哇,多么棒的答案啊。我可能需要一些时间来阅读和吸收它,但这太好了。谢谢! - user5009410
作为提示:完成Scala的Coursera课程,非常不错,我自己也做过! - zmo
1
这意味着你不能在实例内修改它们,因此它们对于所有实例都是相同的。这并不正确。somethinganother取决于构造函数的参数A,因此它们对于每个实例可能是不同的(尽管是不可变的)。 - Kolmar
因此,对于您的所有实例都是相同的val x: myClass = new myClass(Array(1)){ override val someName = "not blah" } - senia
xmyClass 的一个实例,它具有不同的 someName 属性。因此,“对于您的所有实例都是相同的”并不完全正确。 - senia
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接