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 ';' ;
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式的一个特例,其中一个是void
types。 语言对待陈述的倾向往往是不同的,如果把它们恰当地推广,情况会更好。
例如,在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
的可能性? 是。 它所要做的就是要求返回后跟一个void
types的expression式。 default(void)
的结果是default(void)
types的,传入的func需要是Func<TValue, void>
(这相当于Action<TValue>
)。
其他一些答案意味着你不能像expression式一样链接语句,但是我不确定这个想法是从哪里来的。 我们可以想到的;
在作为二进制中缀运算符的语句之后出现,取两个void
types的expression式,并将它们组合成void
types的单个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/else
,case
- 迭代语句是
while
,do...while
,for (...)
- 跳转语句是
break
,continue
,return
(可以返回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式。
为了改进和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式只计算一个值。