我问的是关于c#的问题,但我认为它在大多数其他语言中都是一样的。
有人对表达式和语句有很好的定义吗?它们的区别是什么?
我问的是关于c#的问题,但我认为它在大多数其他语言中都是一样的。
有人对表达式和语句有很好的定义吗?它们的区别是什么?
当前回答
表达式可以求值得到一个值,而语句不返回值(它们是void类型)。
当然,函数调用表达式也可以被视为语句,但除非执行环境有一个特殊的内置变量来保存返回值,否则无法检索它。
面向语句的语言要求所有过程都是语句列表。面向表达式的语言,可能是所有的函数式语言,都是表达式的列表,或者在LISP的情况下,是一个表示表达式列表的长s表达式。
尽管这两种类型都可以组合,但只要类型匹配,大多数表达式都可以任意组合。每种类型的语句都有自己的方式来组合其他语句,如果它们可以做到这一切的话。Foreach和if语句要么要求单个语句,要么要求所有子语句一个接一个地放入语句块中,除非子语句允许它们自己的子语句。
语句还可以包括表达式,而表达式实际上不包括任何语句。不过,lambda表达式是一个例外,它表示一个函数,因此可以包括函数可以包含的任何东西,除非语言只允许有限的lambdas,比如Python的单表达式lambdas。
在基于表达式的语言中,你所需要的只是一个函数的单个表达式,因为所有的控制结构都返回一个值(其中很多返回NIL)。不需要return语句,因为函数中最后求值的表达式就是返回值。
其他回答
表达式:求值为某个值的东西。例如:1 + 2 / x 语句:执行某些操作的代码行。例如:GOTO 100
在最早的通用编程语言(如FORTRAN)中,这种区别是非常明显的。在FORTRAN中,一条语句是一个执行单元,是你所做的一件事。它不被称为“线”的唯一原因是因为有时它跨越多条线。一个表达式本身什么都做不了……你必须把它赋值给一个变量。
1 + 2 / X
是FORTRAN中的一个错误,因为它不做任何事情。你必须对这个表达做些什么:
X = 1 + 2 / X
FORTRAN没有我们今天所知道的语法——这个想法和巴克斯-诺尔表单(BNF)一起被发明出来,作为algolo -60定义的一部分。在这一点上,语义上的区别(“有一个值”和“做某事”)被庄严地体现在语法中:一种短语是表达式,另一种是语句,解析器可以区分它们。
后来语言的设计者模糊了这种区别:他们允许语法表达式做事情,允许有值的语法语句。 现存最早的流行语言例子是C语言。C语言的设计者意识到,如果允许你求一个表达式的值,然后放弃结果,那也没有什么害处。在C语言中,每个语法表达式都可以通过在后面加上分号而变成语句:
1 + 2 / x;
是一个完全合法的声明,即使绝对不会发生任何事情。类似地,在C语言中,表达式可以有副作用——它可以改变一些东西。
1 + 2 / callfunc(12);
因为callfunc可以做一些有用的事情。
一旦您允许任何表达式作为语句,您也可以在表达式中允许赋值操作符(=)。这就是为什么C允许你做
callfunc(x = 2);
这将计算表达式x = 2(将2的值赋给x),然后将该2传递给函数callfunc。
这种表达式和语句的模糊出现在所有的C语言衍生物(C、c++、c#和Java)中,它们仍然有一些语句(如while),但允许几乎任何表达式用作语句(在c#中,只有赋值、调用、自增和自减表达式可以用作语句;参见Scott Wisniewski的回答)。
拥有两个“语法类别”(这是语句和表达式这类东西的专业名称)可能会导致重复工作。例如,C语言中有两种形式的条件句,一种是语句形式
if (E) S1; else S2;
以及表达式形式
E ? E1 : E2
有时人们希望复制不存在的内容:例如,在标准C中,只有语句可以声明一个新的局部变量——但是这种能力非常有用,可以使用 GNU C编译器提供了一个GNU扩展,允许表达式声明局部变量。
Designers of other languages didn't like this kind of duplication, and they saw early on that if expressions can have side effects as well as values, then the syntactic distinction between statements and expressions is not all that useful—so they got rid of it. Haskell, Icon, Lisp, and ML are all languages that don't have syntactic statements—they only have expressions. Even the class structured looping and conditional forms are considered expressions, and they have values—but not very interesting ones.
关于基于表达式的语言的一些事情:
最重要的是:所有内容都返回一个值
用于分隔代码块和表达式的花括号和大括号之间没有区别,因为所有内容都是表达式。不过,这并不会阻止词法作用域:例如,可以为包含其定义的表达式和该表达式中包含的所有语句定义局部变量。
在基于表达式的语言中,所有内容都返回一个值。这一开始可能有点奇怪——(FOR i = 1 TO 10 DO (print i))返回什么?
一些简单的例子:
(1)返回1 (1 + 1)返回2 (1 == 1)返回TRUE (1 == 2)返回FALSE (IF 1 == 1 THEN 10 ELSE 5)返回10 (IF 1 == 2 THEN 10 ELSE 5)返回5
还有一些更复杂的例子:
Some things, such as some function calls, don't really have a meaningful value to return (Things that only produce side effects?). Calling OpenADoor(), FlushTheToilet() or TwiddleYourThumbs() will return some sort of mundane value, such as OK, Done, or Success. When multiple unlinked expressions are evaluated within one larger expression, the value of the last thing evaluated in the large expression becomes the value of the large expression. To take the example of (FOR i = 1 TO 10 DO (print i)), the value of the for loop is "10", it causes the (print i) expression to be evaluated 10 times, each time returning i as a string. The final time through returns 10, our final answer
通常需要稍微改变一下心态,才能最大限度地利用基于表达式的语言,因为所有东西都是表达式,这使得“内联”很多东西成为可能
举个简单的例子:
FOR i = 1 to (IF MyString == "Hello, World!"然后就有10个人这样做了 ( LotsOfCode )
非基于表达式的替换是否完全有效
IF MyString == "Hello, World!"THEN TempVar = 10 ELSE TempVar = 5 FOR i = 1 TO TempVar DO ( LotsOfCode )
在某些情况下,基于表达式的代码所允许的布局对我来说感觉更自然
当然,这可能导致疯狂。作为基于表达式的脚本语言MaxScript的爱好项目的一部分,我设法想出了这个怪物行
IF FindSectionStart "rigidifiers" != 0 THEN FOR i = 1 TO (local rigidifier_array = (FOR i = (local NodeStart = FindsectionStart "rigidifiers" + 1) TO (FindSectionEnd(NodeStart) - 1) collect full_array[i])).count DO
(
LotsOfCode
)
在面向语句的编程语言中,代码块被定义为语句列表。换句话说,语句是可以放入代码块而不会导致语法错误的一段语法。
维基百科对statement这个词的定义类似
在计算机编程中,语句是命令式编程语言的语法单位,它表示要执行的某些操作。用这种语言编写的程序由一个或多个语句的序列组成
注意后一种说法。(尽管在这种情况下,“一个程序”在技术上是错误的,因为C和Java都拒绝一个不包含任何语句的程序。)
维基百科对表达式的定义是
编程语言中的表达式是一个语法实体,可以对其求值以确定其值
然而,这是错误的,因为在Kotlin中,throw new Exception("")是一个表达式,但当求值时,它只是抛出一个异常,从不返回任何值。
在静态类型编程语言中,每个表达式都有一个类型。然而,这个定义在动态类型编程语言中不起作用。
就我个人而言,我将表达式定义为一段语法,它可以由运算符或函数调用组成,以产生更大的表达式。这其实和维基百科对表达式的解释很相似:
它是一个或多个常量、变量、函数和操作符的组合,编程语言解释(根据其特定的优先级和关联规则)并计算产生(在有状态环境中为“返回”)另一个值
但是,问题是在C编程语言中,给定一个函数执行如下内容:
void executeSomething(void){
return;
}
executessomething()是表达式还是语句?根据我的定义,它是一个语句,因为根据微软C引用语法的定义,
不能以任何方式使用具有void类型的表达式的(不存在的)值,也不能将void表达式(通过隐式或显式转换)转换为除void以外的任何类型
但同一页明确指出,这样的语法是一个表达式。
你可以在维基百科上找到这个,但是表达式被求值为某个值,而语句没有求值。
因此,表达式可以用在语句中,但不能用在语句中。
请注意,一些语言(如Lisp,我相信Ruby,以及许多其他语言)并不区分语句和表达式……在这样的语言中,所有东西都是一个表达式,并且可以与其他表达式连接。
为了改进和验证我之前的回答,编程语言术语的定义应该从计算机科学类型理论中解释。
表达式具有除Bottom类型以外的其他类型,即它有一个值。语句具有Unit或Bottom类型。
由此可见,语句只有在产生副作用时才能在程序中发挥作用,因为它要么不能返回值,要么只返回Unit类型的值,而Unit类型的值要么不可赋值(在某些语言中,如C的void),要么可以存储以用于语句的延迟求值。
显然,@pragma或/*comment*/没有类型,因此与语句有所区别。因此,唯一没有副作用的语句类型是非操作。非手术治疗只能作为未来副作用的占位符。由于声明而采取的任何其他行动都是副作用。同样,编译器提示,例如@pragma,不是语句,因为它没有类型。