为什么没有我++在斯卡拉?
我只是想知道为什么没有 i++
来增加数字。据我所知,Ruby 或 Python 等语言不支持它,因为它们是动态类型的。所以很明显我们不能编写像 i++
这样的代码,因为 i
可能是一个字符串或其他东西。但 Scala 是静态类型的——编译器绝对可以推断出将 ++
放在变量后面是否合法。
那么,为什么 Scala 中不存在 i++
呢?
I just wonder why there is no i++
to increase a number. As what I know, languages like Ruby or Python doesn't support it because they are dynamically typed. So it's obviously we cannot write code like i++
because maybe i
is a string or something else. But Scala is statically typed - the compiler absolutely can infer that if it is legal or not to put ++
behind a variable.
So, why doesn't i++
exist in Scala?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
Scala 没有
i++
因为它是一种函数式语言,并且在函数式语言中,避免了有副作用的操作(在纯函数式语言中,根本不允许有任何副作用)。i++
的副作用是i
现在比以前大 1。相反,您应该尝试使用不可变对象(例如val
而不是var
)。此外,Scala 并不真正需要
i++
,因为它提供了控制流结构。在 Java 和其他语言中,您经常需要i++
来构造迭代数组的while
和for
循环。然而,在 Scala 中,您可以直接说出您的意思:for(x <- someArray)
或someArray.foreach
或类似的内容。i++
在命令式编程中很有用,但是当你达到更高的水平时,它很少是必要的(在 Python 中,我从来没有发现自己需要它一次)。您发现
++
可以 出现在 Scala 中,但这并不是因为它没有必要,而且只会阻塞语法。如果您确实需要它,请说i += 1
,但由于 Scala 更频繁地调用不可变和丰富的控制流进行编程,因此您应该很少需要这样做。你当然可以自己定义它,因为运算符实际上只是 Scala 中的方法。Scala doesn't have
i++
because it's a functional language, and in functional languages, operations with side effects are avoided (in a purely functional language, no side effects are permitted at all). The side effect ofi++
is thati
is now 1 larger than it was before. Instead, you should try to use immutable objects (e.g.val
notvar
).Also, Scala doesn't really need
i++
because of the control flow constructs it provides. In Java and others, you needi++
often to constructwhile
andfor
loops that iterate over arrays. However, in Scala, you can just say what you mean:for(x <- someArray)
orsomeArray.foreach
or something along those lines.i++
is useful in imperative programming, but when you get to a higher level, it's rarely necessary (in Python, I've never found myself needing it once).You're spot on that
++
could be in Scala, but it's not because it's not necessary and would just clog up the syntax. If you really need it, sayi += 1
, but because Scala calls for programming with immutables and rich control flow more often, you should rarely need to. You certainly could define it yourself, as operators are indeed just methods in Scala.当然,如果您真的想要的话,您可以在 Scala 中实现:
就这样:
无需对变量诉诸暴力。
Of course you can have that in Scala, if you really want:
And here you go:
No need to resort to violence against variables.
Scala 完全能够解析
i++
,并且只需对语言进行少量修改,就可以修改变量。但有各种各样的理由不这样做。首先,它只节省了一个字符,
i++
与i+=1
相比,这对于添加新的语言功能来说并不算节省太多。其次,
++
运算符在集合库中广泛使用,其中xs ++ ys
接受集合xs
和ys 并生成一个包含两者的新集合。
第三,Scala 试图鼓励您而不是强迫您以函数式方式编写代码。
i++
是一个可变操作,因此与 Scala 让它变得特别简单的思想不一致。 (同样,语言功能允许++
改变变量。)Scala is perfectly capable of parsing
i++
and, with a small modification to the language, could be made to modify a variable. But there are a variety of reasons not to.First, it saves only one character,
i++
vs.i+=1
, which is not very much savings for adding a new language feature.Second, the
++
operator is widely used in the collections library, wherexs ++ ys
takes collectionxs
andys
and produces a new collection that contains both.Third, Scala tries to encourage you, without forcing you, to write code in a functional way.
i++
is a mutable operation, so it's inconsistent with the idea of Scala to make it especially easy. (Likewise with a language feature that would allow++
to mutate a variable.)Scala 没有
++
运算符,因为无法在其中实现。编辑:正如刚才针对此答案所指出的,Scala 2.10.0 可以通过使用宏来实现增量运算符。有关详细信息,请参阅此答案,并将以下所有内容视为 Scala 2.10.0 之前的版本。
让我详细说明一下,我将严重依赖 Java,因为它实际上也遇到同样的问题,但如果我使用 Java 示例,人们可能会更容易理解它。
首先,需要注意的是,Scala 的目标之一是“内置”类不得具有库无法复制的任何功能。当然,在 Scala 中,
Int
是一个类,而在 Java 中,int
是一个基元——一种完全不同于类的类型。因此,为了让 Scala 支持
i++
对于Int
类型的i
,我应该能够创建自己的类MyInt
也支持同样的方法。这是 Scala 的驱动设计目标之一。现在,Java 自然不支持符号作为方法名称,因此我们将其称为
incr()
。我们的目的是尝试创建一个方法incr()
,使得y.incr()
的工作方式与i++
类似。这是第一步:
我们可以用这个来测试它:
一切似乎也都有效:
现在,我将展示问题所在。让我们更改演示程序,并将
Incrementable
与int
进行比较:正如我们在输出中看到的,
Incrementable
和int< /code> 的行为有所不同:
问题是我们通过改变
Incrementable
来实现incr()
,这不是基元的工作方式。Incrementable
需要是不可变的,这意味着incr()
必须生成一个新对象。让我们做一个天真的改变:然而,这不起作用:
问题是,虽然
incr()
创建了一个新对象,但该新对象尚未被创建。 分配给i
。 Java 或 Scala 中没有现有的机制允许我们使用与++
完全相同的语义来实现此方法。现在,这并不意味着 Scala 不可能让这样的事情成为可能。如果 Scala 支持通过引用传递参数(请参阅这篇维基百科文章中的“通过引用调用”),就像 C++ 一样,那么我们就可以实现它!
这是一个虚构的实现,假设与 C++ 中的引用表示法相同。
这要么需要 JVM 支持,要么需要 Scala 编译器上的一些严格的机制。
事实上,Scala 所做的事情与创建闭包时所需的类似 - 其后果之一是原始的 Int 被装箱,可能会带来严重的性能问题影响。
例如,考虑以下方法:
传递给
foreach
,{ n =>; 的代码sum += n }
不是此方法的一部分。foreach
方法采用Function1
类型的对象,其apply
方法实现了这一小段代码。这意味着{ n =>; sum += n }
不仅在不同的方法上,而且在完全不同的类上!然而,它可以改变sum
的值,就像++
运算符需要的那样。如果我们使用 javap 来查看它,我们会看到以下内容:
请注意,它不是创建一个
int
局部变量,而是创建一个IntRef
在堆上(0 处),这是对 int 进行装箱。真正的int
位于IntRef.elem
内部,正如我们在 25 中看到的那样。让我们看看用 while 循环实现同样的事情,以明确区别:变成:
没有对象上面的创建,不需要从堆中获取东西。
因此,总而言之,Scala 需要额外的功能来支持用户可以定义的增量运算符,因为它避免提供外部库无法使用的自己的内置类功能。其中一项功能是按引用传递参数,但 JVM 不提供对此的支持。 Scala 执行类似于按引用调用的操作,为此它使用装箱,这会严重影响性能(很可能会出现增量运算符!)。因此,在缺乏 JVM 支持的情况下,这种可能性不大。
作为补充说明,Scala 具有明显的功能倾向,优先考虑不变性和引用透明性,而不是可变性和副作用。通过引用调用的唯一目的是对调用者造成副作用!虽然这样做可以在许多情况下带来性能优势,但它非常违背 Scala 的原则,因此我怀疑按引用调用是否会成为其中的一部分。
Scala doesn't have a
++
operator because it is not possible to implement one in it.EDIT: As just pointed out in response to this answer, Scala 2.10.0 can implement an increment operator through use of macros. See this answer for details, and take everything below as being pre-Scala 2.10.0.
Let me elaborate on this, and I'll rely heavily on Java, since it actually suffers from the same problem, but it might be easier for people to understand it if I use a Java example.
To start, it is important to note that one of the goals of Scala is that the "built-in" classes must not have any capability that could not be duplicated by a library. And, of course, in Scala an
Int
is a class, whereas in Java anint
is a primitive -- a type entirely distinct from a class.So, for Scala to support
i++
fori
of typeInt
, I should be able to create my own classMyInt
also supporting the same method. This is one of the driving design goals of Scala.Now, naturally, Java does not support symbols as method names, so let's just call it
incr()
. Our intent then is to try to create a methodincr()
such thaty.incr()
works just likei++
.Here's a first pass at it:
We can test it with this:
Everything seems to work, too:
And, now, I'll show what the problem is. Let's change our demo program, and make it compare
Incrementable
toint
:As we can see in the output,
Incrementable
andint
are behaving differently:The problem is that we implemented
incr()
by mutatingIncrementable
, which is not how primitives work.Incrementable
needs to be immutable, which means thatincr()
must produce a new object. Let's do a naive change:However, this doesn't work:
The problem is that, while,
incr()
created a new object, that new object hasn't been assigned toi
. There's no existing mechanism in Java -- or Scala -- that would allow us to implement this method with the exact same semantics as++
.Now, that doesn't mean it would be impossible for Scala to make such a thing possible. If Scala supported parameter passing by reference (see "call by reference" in this wikipedia article), like C++ does, then we could implement it!
Here's a fictitious implementation, assuming the same by-reference notation as in C++.
This would either require JVM support or some serious mechanics on the Scala compiler.
In fact, Scala does something similar to what would be needed that when it create closures -- and one of the consequences is that the original
Int
becomes boxed, with possibly serious performance impact.For example, consider this method:
The code being passed to
foreach
,{ n => sum += n }
, is not part of this method. The methodforeach
takes an object of the typeFunction1
whoseapply
method implements that little code. That means{ n => sum += n }
is not only on a different method, it is on a different class altogether! And yet, it can change the value ofsum
just like a++
operator would need to.If we use
javap
to look at it, we'll see this:Note that instead of creating an
int
local variable, it creates anIntRef
on the heap (at 0), which is boxing theint
. The realint
is insideIntRef.elem
, as we see on 25. Let's see this same thing implemented with a while loop to make clear the difference:That becomes:
No object creation above, no need to get something from the heap.
So, to conclude, Scala would need additional capabilities to support an increment operator that could be defined by the user, as it avoids giving its own built-in classes capabilities not available to external libraries. One such capability is passing parameters by-reference, but JVM does not provide support for it. Scala does something similar to call by-reference, and to do so it uses boxing, which would seriously impact performance (something that would most likely come up with an increment operator!). In the absence of JVM support, therefore, that isn't much likely.
As an additional note, Scala has a distinct functional slant, privileging immutability and referential transparency over mutability and side effects. The sole purpose of call by-reference is to cause side effects on the caller! While doing so can bring performance advantages in a number of situations, it goes very much against the grain of Scala, so I doubt call by-reference will ever be part of it.
其他答案已经正确指出,
++
运算符在函数式编程语言中既不是特别有用,也不理想。我想补充一点,从 Scala 2.10 开始,如果您愿意,您可以添加++
运算符。方法如下:您需要一个隐式宏,将整数转换为具有
++
方法的实例。++
方法由宏“编写”,该宏可以访问调用++
方法的变量(而不是其值)。这是宏的实现:现在,只要隐式转换宏在作用域内,您就可以编写
Other answers have already correctly pointed out that a
++
operator is neither particularly useful nor desirable in a functional programming language. I would like to add that since Scala 2.10, you can add a++
operator, if you want to. Here is how:You need an implicit macro that converts ints to instances of something that has a
++
method. The++
method is "written" by the macro, which has access to the variable (as opposed to its value) on which the++
method is called. Here is the macro implementation:Now, as long as the implicit conversion macro is in scope, you can write
Rafe 的回答对于为什么像 i++ 这样的东西不属于 Scala 的基本原理是正确的。不过我有一点挑剔。实际上不可能在不改变语言的情况下在 Scala 中实现 i++。
在Scala中,++是一个有效的方法,没有方法意味着赋值。只有
=
可以做到这一点。C++ 和 Java 等语言将
++
特别视为递增和赋值。 Scala 以不一致的方式特殊对待=
。在 Scala 中,当您编写
i += 1
时,编译器首先在 Int 上查找名为+=
的方法。它不在那里,所以接下来它在=
上发挥了魔力,并尝试编译该行,就好像它读取i = i + 1
一样。如果您编写i++
,那么 Scala 将调用i
上的方法++
并将结果分配给...无。因为只有=
表示赋值。您可以编写i ++= 1
但这样就达不到目的了。Scala 支持像
+=
这样的方法名称这一事实已经引起争议,有些人认为这是运算符重载。他们可以为++
添加特殊行为,但这样它就不再是有效的方法名称(如=
),这将是另一件需要记住的事情。Rafe's answer is true about the rationale for why something like i++ doesn't belong in Scala. However I have one nitpick. It's actually not possible to implement i++ in Scala without changing the language.
In Scala, ++ is a valid method, and no method implies assignment. Only
=
can do that.Languages like C++ and Java treat
++
specially to mean both increment and assign. Scala treats=
specially, and in an inconsistent way.In Scala when you write
i += 1
the compiler first looks for a method called+=
on the Int. It's not there so next it does it's magic on=
and tries to compile the line as if it readi = i + 1
. If you writei++
then Scala will call the method++
oni
and assign the result to... nothing. Because only=
means assignment. You could writei ++= 1
but that kind of defeats the purpose.The fact that Scala supports method names like
+=
is already controversial and some people think it's operator overloading. They could have added special behavior for++
but then it would no longer be a valid method name (like=
) and it would be one more thing to remember.有相当多的语言不支持++表示法,例如Lua。在支持它的语言中,它经常是混乱和错误的根源,因此它作为语言功能的质量是值得怀疑的,与
i += 1
甚至只是的替代方案相比>i = i + 1
,保存这些次要字符是相当没有意义的。这与语言的类型系统完全无关。虽然大多数静态类型语言确实提供了这些功能,而大多数动态类型却没有提供,但这只是一种相关性,而绝对不是原因。
Quite a few languages do not support the ++ notation, such as Lua. In languages in which it is supported, it is frequently a source of confusion and bugs, so it's quality as a language feature is dubious, and compared to the alternative of
i += 1
or even justi = i + 1
, the saving of such minor characters is fairly pointless.This is not at all relevant to the type system of the language. While it's true that most static type languages do offer and most dynamic types don't, that's a correlation and definitely not a cause.
Scala 鼓励使用 FP 风格,而
i++
当然不是。Scala encourages using of FP style, which
i++
certainly is not.要问的问题是为什么应该有这样的运算符,而不是为什么不应该有。 Scala 会因此得到改进吗?
++
运算符是单一用途的,使用可以更改变量值的运算符可能会导致问题。编写令人困惑的表达式很容易,即使该语言定义了 i = i + i++ 的含义,例如,也需要记住很多详细规则。顺便说一句,你对 Python 和 Ruby 的推理是错误的。在 Perl 中,您可以编写
$i++
或++$i
就可以了。如果$i
结果无法递增,则会出现运行时错误。它不在 Python 或 Ruby 中,因为语言设计者认为这不是一个好主意,而不是因为它们像 Perl 一样是动态类型的。The question to ask is why there should be such an operator, not why there shouldn't be. Would Scala be improved by it?
The
++
operator is single-purpose, and having an operator that can change the value of a variable can cause problems. It's easy to write confusing expressions, and even if the language defines whati = i + i++
means, for example, that's a lot of detailed rules to remember.Your reasoning on Python and Ruby is wrong, by the way. In Perl, you can write
$i++
or++$i
just fine. If$i
turns out to be something that can't be incremented, you get a run-time error. It isn't in Python or Ruby because the language designers didn't think it was a good idea, not because they're dynamically typed like Perl.不过你可以模拟它。举一个简单的例子:
添加一些隐式转换就可以了。然而,这种问题将问题转变为:为什么没有具有此功能的可变 RichInt?
You could simulate it, though. As a trivial example:
Add some implicit conversions and you're good to go. However, this sort of changes the question into: why isn't there a mutable RichInt with this functionality?
正如另一个答案所暗示的那样,增量运算符(如
i++
中所示)是——而不一定是因为这样的运算符与拥有一样有用,比如说一般的加法和减法。尽管某些面向对象语言(例如 Java 和 C#)也有增量运算符(通常借用自 C),但并非所有语言都有(例如 Ruby)。
As another answer suggests, the increment operator, as found in
i++
, was—and not necessarily because such an operator is as useful to have as, say, general addition and subtraction. Although certain object-oriented languages (such as Java and C#) also have an increment operator (often borrowed from C), not all do (such as Ruby).