expression与声明

我问的问候C#,但我认为它在大多数其他语言相同。

有没有人有一个好的expression声明的定义,有什么区别?

expression式:评估为某个值的东西。 例如: 1 + 2 / x
声明:一行代码,做一些事情。 例如: GOTO 100

在最早的通用编程语言,如FORTRAN中,这个区别非常清晰。 在FORTRAN,一个陈述是一个执行单位,你做的一件事情。 它不被称为“行”的唯一原因是因为有时它跨越了多行。 一个expression式本身无法做任何事情……你必须把它分配给一个variables。

1 + 2 / X

在FORTRAN中是错误的,因为它什么都不做。 你必须用这个expression方式做点什么:

X = 1 + 2 / X

FORTRAN没有我们今天所知的语法 – 这个想法和Backus-Naur Form(BNF)一起被发明,作为Algol-60定义的一部分。 在这一点上, 语义上的区别(“有价值”与“做某事”)在语法上是一致的 :一种短语是一种expression,另一种是语句,分析者可以把它们分开。

后来的语言devise师模糊了这种区别:它们允许语法expression式做事,并且允许具有值的语法语句。 最早stream行的stream行语言的例子仍然是C.C的devise者意识到,如果允许您评估一个expression式并丢弃结果,就不会造成任何伤害。 在C语言中,每一个句法expression式都可以作为一个声明,只需要在最后加上一个分号即可:

1 + 2 / x;

是一个完全合法的声明,即使绝对没有事情会发生。 同样,在C中,expression式可能会有副作用 – 它可以改变某些东西。

1 + 2 / callfunc(12);

因为callfunc可能只是做一些有用的事情。

一旦你允许任何expression式成为一个语句,你也可以在expression式中允许赋值运算符(=)。 这就是为什么C让你做这样的事情

callfunc(x = 2);

这将计算expression式x = 2(将值2赋值给x),然后将(2)传递给函数callfunc

expression式和语句的模糊化发生在所有C语言衍生物(C,C ++,C#和Java)中,它们仍然有一些语句(如while ),但几乎允许任何expression式用作语句(仅在C#中赋值,调用,递增和递减expression式可以用作语句;参见Scott Wisniewski的答案)。

有两个“语法范畴”(这是类似事物陈述和expression的技术名称)会导致重复工作。 例如,C有两种forms的条件语句forms

 if (E) S1; else S2; 

和expressionforms

 E ? E1 : E2 

有时候人们想要重复的东西不在那里:例如,在标准C中,只有一个语句可以声明一个新的局部variables – 但是这个function足够有用,GNU C编译器提供了一个GNU扩展,使得expression式能够声明局部variables也是如此。

其他语言的devise者不喜欢这种重复,他们早就看到,如果expression式可以有副作用和价值,那么语句和expression式之间的语法区别并不是那么有用 – 所以他们摆脱了它。 Haskell,Icon,Lisp和ML都是没有语法语句的语言 – 它们只有expression式。 即使是类结构化的循环和条件forms也被认为是expression式,并且它们具有值 – 但不是非常有趣的。

我想对乔尔上面的答案做一个小小的修改。

C#不允许将所有expression式用作语句。 特别是,只能使用赋值,调用,增量和减量expression式作为语句。

例如,C#编译器会将以下代码标记为语法错误:

1 + 2;

  • expression式是任何产生值的东西:2 + 2
  • 声明是程序执行的基本“块”之一。

注意在C中,“=”实际上是一个运算符,它有两个作用:

  • 返回右边子expression式的值。
  • 将右侧子expression式的值复制到左侧的variables中。

这里是ANSI C语法的摘录。 你可以看到C没有多种不同的语句……程序中的大多数语句都是expression式语句,即在末尾带有分号的expression式。

 statement : labeled_statement | compound_statement | expression_statement | selection_statement | iteration_statement | jump_statement ; expression_statement : ';' | expression ';' ; 

http://www.lysator.liu.se/c/ANSI-C-grammar-y.html

expression式是返回值的东西,而语句不是。

例如:

 1 + 2 * 4 * foo.bar() //Expression foo.voidFunc(1); //Statement 

两者之间的大交易是你可以把expression连在一起,而陈述是不能链接的。

你可以在维基百科上find它,但expression式被评估为一些值,而语句没有评估值。

因此,可以在语句中使用expression式,而不是用相反的方式。

请注意,有些语言(比如Lisp,我相信Ruby和许多其他语言)不会区分语句和expression式…在这些语言中,一切都是expression式,可以与其他expression式链接。

为了解释expression式与语句的可组合性(可链接性)之间的重要区别,我最喜欢的参考资料是John Backus的图灵(Turing)奖论文, Can programming可以从冯诺依曼风格中解放出来吗?

强制性语言(Fortran,C,Java,…)强调构造程序的语句,并将expression式作为一种事后思考。 function语言强调expression。 function语言具有如此强大的expression,而语句可以完全消除。

简单地说:一个expression式评估为一个值,一个声明不是。

可以评估expression式来获得一个值,而语句不返回一个值(它们是voidtypes的)。

函数调用expression式当然也可以看作是语句,但除非执行环境有一个特殊的内置variables来保存返回的值,否则无法检索它。

面向语句的语言要求所有程序都是语句清单。 面向expression的语言,可能是所有的函数式语言,都是expression式列表,或者在LISP的情况下,是一个表示expression式列表的长Sexpression式。

虽然两种types都可以组成,但只要types匹配,大多数expression式可以任意组成。 每种types的陈述都有其自己的方式来编写其他陈述,如果他们能做到的话。 每一条语句都需要一个单独的语句,或者所有的从属语句一个接一个地在一个语句块中,除非子语句允许自己的子语句。

语句也可以包含expression式,其中expression式并不包含任何语句。 但是,一个例外是lambdaexpression式,它表示一个函数,所以可以包含任何函数可以使用的东西,除非语言只允许有限的lambdaexpression式,如Python的单expression式lambdaexpression式。

在一个基于expression式的语言中,所有你需要的是一个函数的单一expression式,因为所有的控制结构都返回一个值(很多都返回NIL)。 因为函数中最后一个求值的expression式是返回值,所以不需要返回语句。

有关expression式语言的一些事情:


最重要的是:一切都回报一个价值


用大括号和大括号来区分代码块和expression式是没有区别的,因为一切都是expression式。 尽pipe如此,这并不妨碍词法作用域:例如,可以为包含其定义的expression式定义一个局部variables,并且可以为其定义所有语句。


在基于expression式的语言中,一切都返回一个值。 这可能有点奇怪 – 什么(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

一个更复杂的例子:

  • 有些东西,比如一些函数调用,实际上并没有一个有意义的值返回(只产生副作用的东西?)。 调用OpenADoor(), FlushTheToilet()TwiddleYourThumbs()将返回某种普通的值,比如OK,Done或Success。
  • 当在一个较大的expression式中计算多个未链接expression式时,大expression式中最后一个评估对象的值将成为大expression式的值。 以(FOR i = 1 TO 10 DO (print i))为例,for循环的值是“10”,它使得(print i)expression式被评估10次,每次返回i作为串。 最后一次通过退货10 ,我们的最终答案

为了充分利用基于expression式的语言,通常需要稍微改变一下思维模式,因为事实是一切都是expression式,所以可以“内联”很多东西

举一个简单的例子:

  FOR i = 1 to (IF MyString == "Hello, World!" THEN 10 ELSE 5) DO ( LotsOfCode ) 

是一个完全有效的替代基于非expression式

 IF MyString == "Hello, World!" THEN TempVar = 10 ELSE TempVar = 5 FOR i = 1 TO TempVar DO ( LotsOfCode ) 

在某些情况下,基于expression式代码允许的布局对我来说更为自然

当然,这可能会导致疯狂。 作为一个名为MaxScript的基于expression式的脚本语言的爱好项目的一部分,我设法想出了这个怪物线

 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 ) 

声明是expression式的一个特例,其中一个是voidtypes。 语言对待陈述的倾向往往是不同的,如果把它们恰当地推广,情况会更好。

例如,在C#中,我们有非常有用的Func<T1, T2, T3, TResult>重载通用委托集。 但是我们也必须有一个相应的Action<T1, T2, T3>集合,并且通用的高阶编程必须不断地被复制来处理这个不幸的分支。

简单的例子 – 在调用另一个函数之前检查引用是否为空的函数:

 TResult IfNotNull<TValue, TResult>(TValue value, Func<TValue, TResult> func) where TValue : class { return (value == null) ? default(TValue) : func(value); } 

编译器能否处理TResult void的可能性? 是。 它所要做的就是要求返回后跟一个voidtypes的expression式。 default(void)的结果是default(void)types的,传入的func需要是Func<TValue, void> (这相当于Action<TValue> )。

其他一些答案意味着你不能像expression式一样链接语句,但是我不确定这个想法是从哪里来的。 我们可以想到的; 在作为二进制中缀运算符的语句之后出现,取两个voidtypes的expression式,并将它们组合成voidtypes的单个expression式。

语句 – >指令按顺序
expression式 – >评估返回一个值

语句基本上就像是一个algorithm中的步骤或指令,语句执行的结果就是指令指针的实现(所谓汇编语言)

expression式一开始并不意味着执行顺序,其目的是评估和返回一个值。 在命令式编程语言中,expression式的评估有一个顺序,但这只是因为命令式的模式,但它不是它们的本质。

陈述的例子:

 for goto return if 

(所有这些都意味着执行的行(声明)提前到另一行)

expression式的例子:

 2+2 

(这并不意味着执行的想法,而是意味着评价)

语句是语法上完整的句子。 expression式不是。 例如

 x = 5 

读作“x获得5”。 这是一个完整的句子。 代码

 (x + 5)/9.0 

读出“x加5除以9.0”。 这不是一个完整的句子。 该声明

 while k < 10: print k k += 1 

是一个完整的句子。 请注意,循环标题不是; “而k <10”是一个从属条款。

我更喜欢这个词在forms逻辑意义上的含义。 它是改变计算中的一个或多个variables的状态的一个,使得能够对它们的值做出真或假的陈述。

我想在计算机世界和科学领域总是会出现混乱,因为引入了新的术语或词汇,现有的词语被“重新利用”,或者用户对于他们正在描述的现有的,已经build立的或“适当”的术语是无知的

我对这里的任何答案都不满意。 我看了C ++(ISO 2008)的语法。 但是,也许为了教学和编程的缘故,答案可能足以区分这两个元素(尽pipe现实看起来更复杂)。

一个语句由零个或多个expression式组成,但也可以是其他语言的概念。 这是语法扩展Backus Naurforms(摘录):

 statement: labeled-statement expression-statement <-- can be zero or more expressions compound-statement selection-statement iteration-statement jump-statement declaration-statement try-block 

我们可以在C ++中看到其他被视为语句的概念。

  • expression式语句是自我解释的(语句可以包含零个或多个expression式,仔细阅读语法,这是棘手的)
  • 例如,是一个标签声明
  • select语句if/elsecase
  • 迭代语句whiledo...whilefor (...)
  • 跳转语句breakcontinuereturn (可以返回expression式), goto
  • 声明声明是一组声明
  • try-block是代表try/catch块的语句
  • 而且语法可能还有更多

这是一个摘录显示expression式部分:

 expression: assignment-expression expression "," assignment-expression assignment-expression: conditional-expression logical-or-expression assignment-operator initializer-clause throw-expression 
  • expression式是或经常包含任务
  • 条件expression式 (听起来令人误解)是指使用运算符( +-*/&|&&|| ,…)
  • 扔expression – 呃? throw子句也是一个expression式

声明 ,

声明是构build所有C#程序的程序构build块。 一个语句可以声明一个局部variables或常量,调用一个方法,创build一个对象,或赋值给一个variables,属性或字段。

花括号包围的一系列语句形成一个代码块。 方法体是代码块的一个例子。

 bool IsPositive(int number) { if (number > 0) { return true; } else { return false; } } 

C#中的语句通常包含expression式。 C#中的expression式是包含字面值,简单名称或运算符及其操作数的代码片段。

expression ,

expression式是可以评估为单个值,对象,方法或名称空间的代码片段。 两种最简单的expression方式是文字和简单的名字。 文字是一个没有名字的常数值。

 int i = 5; string s = "Hello World"; 

我和s都是识别局部variables的简单名字。 在expression式中使用这些variables时,将检索variables的值并将其用于expression式。

这是我find的最简单答案之一的总结。

最初由Anders Kaseorg回答

语句是执行某个操作的完整代码行,而expression式是代码的任何部分,其值为一个值。

expression式可以使用运算符“水平地”组合成更大的expression式,而语句只能通过一个接一个地写或者通过块结构“垂直地”组合。

每个expression式都可以用作语句(其效果是评估expression式并忽略结果值),但大多数语句不能用作expression式。

http://www.quora.com/Python-programming-language-1/Whats-the-difference-between-a-statement-and-an-expression-in-Python

为了改进和validation我以前的答案,编程语言术语的定义应该在适用时从计算机科学types理论中解释。

一个expression式的types不是Bottomtypes,即它有一个值。 一个声明有单位或底部types。

由此可见,一个语句在创build副作用时只能在程序中产生任何效果,因为它不能返回值,或者只返回不可分配的单元types的值(在某些语言中一个C的void )或者(比如在Scala中)可以被存储来对该语句进行延迟评估。

很明显, @pragma/*comment*/没有types,因此与语句不同。 因此,唯一没有任何副作用的说法是无效的。 非操作只是作为未来副作用的占位符。 任何其他由于陈述而采取的行动将是一个副作用。 再次,编译器提示(例如@pragma )不是一个声明,因为它没有types。

更确切的说,一个陈述必须有一个“副作用” (即是必要的 ),一个expression式必须一个types(即不是最低types)。

声明的types是单位types,但由于Halting定理单位是虚构的,所以可以说底部types 。


Void不是精确的底部types(它不是所有可能types的子types)。 它存在于没有完整声音types系统的语言中 。 这可能听起来像一个势利的声明,但是完整性(如变异注释)对编写可扩展软件至关重要。

让我们看看维基百科在这个问题上要说些什么。

https://en.wikipedia.org/wiki/Statement_(computer_science);

在计算机编程中,语句是命令式编程语言中最小的独立元素,表示要执行的一些操作

许多语言(例如C)在语句和定义之间作了区分,语句只包含可执行代码和定义,声明一个标识符,而expression式只计算一个值。