我是 Scala 的新手,听说过很多东西都是 Scala 中的对象。我不明白“一切都是对象”的优势是什么?如果一切都不是对象,有哪些事情是我不能做的?欢迎举例。谢谢
5 回答
让“一切”成为对象的好处是,抽象中断的情况要少得多。
例如,方法不是 Java 中的对象。所以如果我有两个字符串,我可以
String s1 = "one";
String s2 = "two";
static String caps(String s) { return s.toUpperCase(); }
caps(s1); // Works
caps(s2); // Also works
因此,我们在制作大写字母的操作中抽象出了字符串标识。但是,如果我们想抽象出操作的身份——也就是说,我们对一个返回另一个字符串的字符串做一些事情,但我们想抽象出细节是什么?现在我们被困住了,因为方法不是 Java 中的对象。
在 Scala 中,方法可以转换为函数,即对象。例如:
def stringop(s: String, f: String => String) = if (s.length > 0) f(s) else s
stringop(s1, _.toUpperCase)
stringop(s2, _.toLowerCase)
现在我们已经抽象出对非空字符串执行一些字符串转换的想法。
如果这是我们需要做的,我们可以列出操作等并传递它们。
还有其他不太重要的情况(对象与类、原始与非、值类等),但最重要的是打破方法和对象之间的区别,以便传递和抽象功能就像传递一样容易围绕和抽象数据。
优点是您没有不同的运算符在您的语言中遵循不同的规则。例如,在 Java 中执行涉及对象的操作时,您使用dot name
调用代码的技术(静态对象仍然使用该dot name
技术,但有时会推断出 thethis object
或 the static object
),而内置项(不是对象)使用不同的方法,即内置运算符操作。
Number one = Integer.valueOf(1);
Number two = Integer.valueOf(2);
Number three = one.plus(two); // if only such methods existed.
int one = 1;
int two = 2;
int three = one + two;
主要区别在于该dot name
技术受多态性、运算符重载、方法隐藏以及您可以使用 Java 对象做的所有好事情的影响。该+
技术是预定义的并且完全不灵活。
+
Scala通过基本上将其作为运算符处理,并定义此类运算符到对象方法dot name
的强大的一对一映射来规避该方法的不灵活性。因此,在 Scala 中,一切都是对象意味着一切都是对象,因此操作
5 + 7
导致创建了两个对象(一个 5 对象和一个 7 对象),使用参数 7 调用 5 个对象的 plus 方法(如果我的 scala 内存正确地为我服务)和一个“12”对象作为值返回5 + 7
手术。
这一切都是对象在函数式编程环境中有很多好处,例如,代码块现在也是对象,使得可以将代码块(没有名称)作为参数来回传递,但仍然绑定到严格的类型检查(代码块只返回Long
或子类String
或其他)。
归根结底,它使某些解决方案非常容易实现,并且由于不需要处理“移入原语、操作、移出原语”编组代码,通常会减轻效率低下的情况。
我想到的一个特定优势(因为您要求提供示例)是 Java 中的原始类型 ( int, boolean ...
) ,Scala 中的对象是可以通过隐式转换添加功能的对象。例如,如果你想向toRoman
int 添加一个方法,你可以编写一个隐式类,如:
implicit class RomanInt(i:Int){
def toRoman = //some algorithm to convert i to a Roman representation
}
然后,您可以从任何Int
文字中调用此方法,例如:
val romanFive = 5.toRoman // V
通过这种方式,您可以“拉皮条”基本类型以使其适应您的需求
除了其他人提出的观点外,我总是强调 Scala 中对所有值的统一处理在一定程度上是一种错觉。在大多数情况下,这是一个非常受欢迎的错觉。Scala 非常聪明地尽可能多地使用真正的 JVM 原语,并且只在必要时执行自动转换(通常称为装箱和拆箱)。
但是,如果自动装箱和拆箱应用的动态模式非常高,则可能会产生与之相关的不良成本(内存和 CPU)。这可以通过使用specialization来部分缓解,当特定类型参数是(程序员指定的)原始类型时,它会创建泛型类的特殊版本。这避免了装箱和拆箱,但代价是.class
正在运行的应用程序中有更多文件。
在 Scala 中,并非所有事物都是对象,尽管 Scala 中的对象多于 Java 中的对象。
对象的优点是它们是状态包,它们也有一些与之相关的行为。通过添加多态性,对象为您提供了更改隐式行为和状态的方法。诗歌说完了,让我们来看一些例子。
该if
语句在 scala 或 java 中都不是对象。如果是这样,您可以对其进行子类化,在其位置注入另一个依赖项,并在您的代码使用该if
语句时使用它来执行诸如记录到文件之类的事情。那不是很神奇吗?在某些情况下,它会帮助您调试东西,而在其他情况下,它会让您的头发变白,然后您才发现有人覆盖了if
.
访问一个无对象、有陈述的世界:想象你最喜欢的 OOP 编程语言。想想它提供的标准库。那里有很多课,对吧?他们提供了定制的方法,对吧?他们接受其他对象的参数,他们创建其他对象。您可以自定义所有这些。你有多态性。现在想象一下,所有的标准库都只是关键字。您将无法自定义几乎一样多的内容,因为您无法覆盖关键字。你会被语言设计者决定实施的任何情况所困,并且你将无助于在那里定制任何东西。这样的语言存在,你很了解它们,它们是类似续集的语言。你几乎不能在那里创建函数,但是为了自定义SELECT
声明,必须出现该语言的新版本,其中包含最需要的功能。这将是一个极端的世界,您只能通过向语言设计人员询问新功能来进行编程(您可能无法获得,因为其他更重要的人需要一些与您想要的不兼容的功能)
总之,并非所有东西都是 scala 中的对象:类、表达式、关键字和包肯定不是。然而,更多的东西是,比如函数。恕我直言,一个很好的经验法则是更多的对象等于更多的灵活性
例如,Python 中的 PS,更多的东西是对象(比如类本身,类似的概念packages
(即 python 模块和包)。你会看到那里,黑魔法更容易做到,这带来了好和不良后果。