Tuyên bố Versus


431

Tôi đang hỏi về c #, nhưng tôi cho rằng nó giống nhau ở hầu hết các ngôn ngữ khác.

Có ai có một định nghĩa tốt về biểu thứcphát biểu và sự khác biệt là gì?


4
Tôi tìm thấy câu trả lời bạn chọn là mơ hồ. Một biểu thức cũng làm một cái gì đó-- nó đánh giá một giá trị. Tôi cung cấp một câu trả lời không mơ hồ.
Shelby Moore III

4
@ShelbyMooreIII - Không mơ hồ và cũng sai. Câu trả lời được chấp nhận được diễn đạt theo cách không chính thức, nhưng cách diễn đạt đó giúp bạn dễ hiểu - và quan trọng nhất, ý nghĩa mà nó truyền tải là chính xác.
Justin Morgan

@JustinMorgan Đáng buồn thay, các định nghĩa trong câu trả lời được chấp nhận rõ ràng cũng sai ("đánh giá một giá trị" / "một dòng mã") cho hầu hết các ngôn ngữ hiện đại bao gồm các ngôn ngữ giống như C: các biểu thức có thể được sử dụng trong ngữ cảnh không được đánh giá và các câu lệnh không có giá trị để làm với dòng. Thậm chí có một số giải thích, câu trả lời ngắn gọn là khó hiểu và sai lệch.
FrankHB

Câu trả lời:


520

Biểu hiện: Một cái gì đó đánh giá một giá trị. Ví dụ: 1 + 2 / x
Statement: Một dòng mã thực hiện điều gì đó. Ví dụ: GOTO 100

Trong các ngôn ngữ lập trình đa mục đích sớm nhất, như FORTRAN, sự khác biệt rất rõ ràng. Trong FORTRAN, một câu lệnh là một đơn vị thực thi, một việc mà bạn đã làm. Lý do duy nhất nó không được gọi là "đường" là vì đôi khi nó kéo dài nhiều dòng. Một biểu thức tự nó không thể làm bất cứ điều gì ... bạn phải gán nó cho một biến.

1 + 2 / X

là một lỗi trong FORTRAN, vì nó không làm gì cả. Bạn phải làm một cái gì đó với biểu hiện đó:

X = 1 + 2 / X

FORTRAN không có ngữ pháp như chúng ta biết ngày nay, ý tưởng đó đã được phát minh, cùng với Backus-Naur Form (BNF), như một phần định nghĩa của Algol-60. Vào thời điểm đó, sự phân biệt ngữ nghĩa ("có giá trị" so với "làm điều gì đó") được quy định theo cú pháp : một loại cụm từ là một biểu thức và một cụm từ khác là một câu lệnh và trình phân tích cú pháp có thể phân biệt chúng.

Các nhà thiết kế của các ngôn ngữ sau này đã làm mờ sự khác biệt: họ cho phép các biểu thức cú pháp thực hiện và họ cho phép các câu cú pháp có giá trị. Ví dụ ngôn ngữ phổ biến sớm nhất vẫn còn tồn tại là C. Các nhà thiết kế của C nhận ra rằng không có tác hại nào được thực hiện nếu bạn được phép đánh giá một biểu thức và vứt bỏ kết quả. Trong C, mọi biểu thức cú pháp có thể được tạo thành một câu lệnh chỉ bằng cách ghép một dấu chấm phẩy dọc theo cuối:

1 + 2 / x;

là một tuyên bố hoàn toàn hợp pháp mặc dù hoàn toàn không có gì sẽ xảy ra. Tương tự, trong C, một biểu thức có thể có tác dụng phụ .

1 + 2 / callfunc(12);

bởi vì callfunccó thể làm điều gì đó hữu ích

Khi bạn cho phép bất kỳ biểu thức nào là một câu lệnh, bạn cũng có thể cho phép toán tử gán (=) bên trong các biểu thức. Đó là lý do tại sao C cho phép bạn làm những việc như

callfunc(x = 2);

Điều này đánh giá biểu thức x = 2 (gán giá trị của 2 cho x) và sau đó chuyển giá trị đó (2) cho hàm callfunc.

Việc làm mờ các biểu thức và câu lệnh này xảy ra trong tất cả các dẫn xuất C (C, C ++, C # và Java), vẫn có một số câu lệnh (như while) nhưng cho phép hầu hết mọi biểu thức được sử dụng làm câu lệnh (chỉ gán C #, các biểu thức gọi, tăng và giảm có thể được sử dụng làm câu lệnh; xem câu trả lời của Scott Wisniewski ).

Có hai "phạm trù cú pháp" (là tên kỹ thuật cho loại câu lệnh và biểu thức) có thể dẫn đến sự trùng lặp nỗ lực. Ví dụ: C có hai dạng điều kiện, dạng câu lệnh

if (E) S1; else S2;

và biểu thức

E ? E1 : E2

Và đôi khi mọi người muốn sao chép không có ở đó: ví dụ, trong tiêu chuẩn C, chỉ một câu lệnh có thể khai báo một biến cục bộ mới nhưng khả năng này đủ hữu ích để trình biên dịch GNU C cung cấp một phần mở rộng GNU cho phép một biểu thức khai báo một biểu thức biến cục bộ là tốt.

Các nhà thiết kế của các ngôn ngữ khác không thích loại trùng lặp này và họ đã sớm nhận ra rằng nếu các biểu thức có thể có tác dụng phụ cũng như các giá trị, thì sự phân biệt cú pháp giữa các câu và biểu thức không phải là tất cả hữu ích vì vậy họ đã loại bỏ nó . Haskell, Icon, Lisp và ML là tất cả các ngôn ngữ không có câu cú pháp, chúng chỉ có các biểu thức. Ngay cả các dạng vòng lặp có cấu trúc và các dạng có điều kiện được coi là các biểu thức và chúng có các giá trị nhưng không phải là các biểu thức rất thú vị.


9
Nếu tôi không hiểu sai về bạn ở đây, bạn dường như cho rằng "(setf (thứ ba foo) 'ngỗng)" là một biểu thức, không phải là một tuyên bố, bởi vì đó là Lisp, "không có câu lệnh" và bởi vì Lisp lớn hơn C một thập kỷ, là "ngôn ngữ phổ biến sớm nhất để làm mờ các dòng [giữa các biểu thức và các tuyên bố]." Có thể giải thích chi tiết về điều đó cho tôi?
cjs

2
@Curt Sampson, bạn đã hỏi đó là một câu hỏi riêng biệt chưa?
Kelly S. Pháp

5
Nếu tôi không nhầm, callfunc(x = 2);đi xtới callfunc, không 2. Nếu xlà một float, callfunc(float)sẽ được gọi, không callfunc(int). Và trong C ++, nếu bạn vượt qua x=yđể func, và funcmất một tài liệu tham khảo và thay đổi nó, nó thay đổi x, không phải y.
Gabriel

Trong câu trả lời ở trên, người ta viết rằng "Haskell, ... là tất cả các ngôn ngữ không có câu cú pháp - chúng chỉ có biểu thức". Tôi tò mò tại sao wheremệnh đề trong haskell được coi là một biểu thức chứ không phải là một tuyên bố. learnyouahaskell.com/syntax-in-fifts#where
skgbanga

@skgbanga Tôi tin rằng wherethực sự là một phần của khai báo hàm, không phải là biểu thức hoặc câu lệnh.
Akangka

22
  • một biểu thức là bất cứ thứ gì mang lại giá trị: 2 + 2
  • một câu lệnh là một trong những "khối" cơ bản của việc thực hiện chương trình.

Lưu ý rằng trong C, "=" thực sự là một toán tử, thực hiện hai điều:

  • trả về giá trị của biểu thức con bên phải.
  • sao chép giá trị của biểu thức con bên phải vào biến ở phía bên trái.

Đây là một trích xuất từ ​​ngữ pháp ANSI C. Bạn có thể thấy rằng C không có nhiều loại câu lệnh khác nhau ... phần lớn các câu lệnh trong một chương trình là các câu lệnh biểu thức, nghĩa là một biểu thức có dấu chấm phẩy ở cuối.

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


2
Logic không chính xác về những gì một tuyên bố là. Một chương trình khai báo cũng có thể thực thi, nhưng một chương trình khai báo không có câu lệnh nào. Một tuyên bố là và "tác dụng phụ" , nghĩa là bắt buộc. xem Câu trả lời của tôi .
Shelby Moore III

15

Biểu thức là một cái gì đó trả về một giá trị, trong khi một câu lệnh thì không.

Ví dụ như:

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

Thỏa thuận lớn giữa hai bên là bạn có thể xâu chuỗi các biểu thức lại với nhau, trong khi các câu lệnh không thể được nối kết.


6
Những tuyên bố chắc chắn có thể bị xiềng xích. {stmt1; stmt2; stmt3;} là một chuỗi và bản thân nó cũng là một câu lệnh (ghép).
Hugh Allen

5
foo.voidFunc(1);là một biểu thức có giá trị void. whileiflà những tuyên bố.
tzot

Tôi tò mò về việc không xâu chuỗi các tuyên bố. Sẽ có cái gì đó như "nếu (x> 1) trở lại;" được coi là xích hai tuyên bố với nhau?
Simon Tewsi

1
@SimonTewsi Tôi tin rằng returnnó được coi là một sự thay thế.
RastaJedi 17/03/19

@SimonTewsi Câu lệnh return ở đây hoàn toàn nằm trong khối câu lệnh if, vì vậy nó là một phần của câu lệnh if, không bị xiềng xích với nó. Trình biên dịch cho phép chúng ta bỏ qua các dấu ngoặc ở đây, vì nó là một khối dòng đơn.
user2597608

9

Bạn có thể tìm thấy điều này trên wikipedia , nhưng các biểu thức được ước tính theo một số giá trị, trong khi các câu lệnh không có giá trị được đánh giá.

Do đó, các biểu thức có thể được sử dụng trong các câu lệnh, nhưng không phải là cách khác.

Lưu ý rằng một số ngôn ngữ (như Lisp và tôi tin rằng Ruby và nhiều ngôn ngữ khác) không phân biệt tuyên bố và biểu thức ... trong các ngôn ngữ đó, mọi thứ đều là biểu thức và có thể được kết nối với các biểu thức khác.


8

Để giải thích về sự khác biệt quan trọng về khả năng kết hợp (tính chuỗi) của biểu thức so với câu lệnh, tài liệu tham khảo yêu thích của tôi là bài viết về giải thưởng Turing của John Backus, lập trình có thể được giải phóng khỏi phong cách von Neumann không? .

Các ngôn ngữ bắt buộc (Fortran, C, Java, ...) nhấn mạnh các câu lệnh để cấu trúc các chương trình và có các biểu thức như một kiểu suy nghĩ sau. Ngôn ngữ chức năng nhấn mạnh biểu thức. Các ngôn ngữ chức năng thuần túy có các biểu thức mạnh mẽ như vậy hơn các câu lệnh có thể được loại bỏ hoàn toàn.


5

Đơn giản là: một biểu thức ước lượng thành một giá trị, một câu lệnh thì không.


Vì vậy, một tuyên bố làm gì? Không có gì?
Shelby Moore III

1
Nó có thể làm một cái gì đó, nhưng nó không đánh giá bất cứ điều gì. Tức là, bạn không thể gán kết quả của nó cho một biến, trong khi bạn có thể với một biểu thức.
Matthew Schinckel

Và do đó, một tuyên bố phải có tác dụng phụ, vì các câu trả lời bỏ phiếu nặng nề của tôi. Những gì tiện ích khác có thể có một tuyên bố có thể có? Ngay cả khi NO-OP được coi là một tuyên bố (nó chỉ là "tuyên bố" trong ngữ pháp chứ không phải ở lớp ngữ nghĩa vì nó bị xóa sau khi phân tích cú pháp và ngữ nghĩa là những gì chúng ta đang thảo luận ở đây), nó sẽ không giải thích điều gì heck các tiện ích chung của một tuyên bố là.
Shelby Moore III

1
@ShelbyMooreIII Tuyên bố không cần làm gì hoặc có tác dụng phụ. ví dụ, {}là một tuyên bố. Đặt từ trong trích dẫn sợ hãi không thay đổi điều đó. Báo cáo là cấu trúc cú pháp với ngữ nghĩa. Không có thứ gọi là "lớp ngữ nghĩa" - bạn dường như đang đề cập đến việc thực thi . Bạn nói rằng bạn đang cố gắng chính xác, nhưng bạn đã thất bại ở đó. Khiếu nại của bạn về "sự thờ ơ của những người bỏ phiếu" là chủ đề quảng cáo thuần túy; bạn không có thông tin về trạng thái tinh thần của downvoters.
Jim Balter

Vâng, mọi người đều sai ngoại trừ sự không trung thực về trí tuệ. {}được định nghĩa là một tuyên bố trong thông số ngôn ngữ C #.
Jim Balter

5

Biểu thức có thể được ước tính để nhận giá trị, trong khi các câu lệnh không trả về giá trị (chúng thuộc loại void ).

Tất nhiên, các biểu thức gọi hàm cũng có thể được coi là câu lệnh, nhưng trừ khi môi trường thực thi có một biến tích hợp đặc biệt để giữ giá trị trả về, không có cách nào để lấy nó.

Các ngôn ngữ hướng phát biểu yêu cầu tất cả các thủ tục phải là một danh sách các câu lệnh. Các ngôn ngữ hướng biểu thức, có lẽ là tất cả các ngôn ngữ chức năng, là danh sách các biểu thức hoặc trong trường hợp của LISP, một biểu thức S dài biểu thị một danh sách các biểu thức.

Mặc dù cả hai loại có thể được soạn thảo, hầu hết các biểu thức có thể được soạn tùy ý miễn là các loại khớp với nhau. Mỗi loại câu lệnh có cách soạn thảo các câu lệnh khác, nếu chúng có thể làm tất cả. Foreach và nếu các câu lệnh yêu cầu một thống kê duy nhất hoặc tất cả các câu lệnh cấp dưới đi trong một khối câu lệnh, lần lượt từng câu lệnh, trừ khi các trạm biến áp cho phép các trạm biến áp riêng của chúng.

Các câu lệnh cũng có thể bao gồm các biểu thức, trong đó một biểu thức không thực sự bao gồm bất kỳ câu lệnh nào. Tuy nhiên, một ngoại lệ sẽ là biểu thức lambda, đại diện cho một hàm và do đó có thể bao gồm mọi thứ mà hàm có thể loại trừ trừ khi ngôn ngữ chỉ cho phép lambdas giới hạn, như lambdas biểu thức đơn của Python.

Trong ngôn ngữ dựa trên biểu thức, tất cả những gì bạn cần là một biểu thức cho một hàm vì tất cả các cấu trúc điều khiển trả về một giá trị (rất nhiều trong số chúng trả về NIL). Không cần câu lệnh return vì biểu thức được đánh giá cuối cùng trong hàm là giá trị trả về.


Loại của một tuyên bố là loại dưới cùng. Voidkhông phải là loại dưới cùng. Xem câu trả lời của tôi .
Shelby Moore III

1
Không phải loại null là loại dưới cùng (giá trị đơn null)? Sẽ không voidgiống với loại đơn vị hơn (nhưng với giá trị duy nhất không thể truy cập được)?
Đánh dấu Cidade

Nếu voidlà kiểu trả về của hàm không bao giờ trả về (ví dụ: hàm throwcó lỗi), thì đó là kiểu dưới cùng . Nếu không thì voidloại đơn vị . Bạn đúng rằng một câu lệnh không thể phân kỳ, có loại đơn vị. Nhưng một tuyên bố có thể phân kỳ là loại dưới cùng. Do Định lý dừng, chúng ta thường không thể chứng minh rằng một hàm không phân kỳ, vì vậy tôi nghĩ đơn vị là hư cấu. Loại dưới cùng không thể có một giá trị, vì vậy nó không thể có một giá trị duy nhất null.
Shelby Moore III

1
Về những gì tôi đã nói ba năm trước, tôi không biết liệu tôi có còn nghĩ rằng các tuyên bố là có một loại khoảng trống hoặc bất kỳ loại nào thực sự không. Trong các ngôn ngữ dựa trên câu lệnh mà tôi quen thuộc, chỉ các giá trị và mọi thứ lưu trữ hoặc trả về một giá trị (ví dụ: biểu thức, biến, thành viên và hàm) có thể có các loại. Tôi thường nghĩ về loại dưới cùng là tập hợp trống (không có giá trị) và vì vậy bất cứ thứ gì không tồn tại về mặt bản chất sẽ có loại này. Một nullgiá trị thực sự là một giả hành biểu thị rằng một tham chiếu đề cập đến một cái gì đó không tồn tại.
Đánh dấu Cidade

1
Đánh dấu tôi đánh giá cao sự hợp lý của phản ứng của bạn. Về cơ bản bạn đã lấy từ ngữ ra khỏi miệng tôi và tôi hy vọng rõ ràng rằng tôi đã thừa nhận với bạn rằng bạn đã đúng để nâng cao điểm đơn vị. Tôi nghĩ rằng chúng tôi đồng ý. Tôi sẽ không bận tâm đến việc đề cập đến điều này, nhưng dường như một số người ở đây nghĩ rằng tôi đang tiêu cực. Tôi chỉ đang cố gắng để thực tế.
Shelby Moore III

4

Một số điều về ngôn ngữ dựa trên biểu thức:


Quan trọng nhất: Mọi thứ trả về một giá trị


Không có sự khác biệt giữa dấu ngoặc nhọn và dấu ngoặc nhọn để phân định khối mã và biểu thức, vì mọi thứ đều là biểu thức. Điều này không ngăn chặn phạm vi từ vựng mặc dù: Một biến cục bộ có thể được xác định cho biểu thức chứa định nghĩa của nó và tất cả các câu lệnh chứa trong đó, ví dụ.


Trong một ngôn ngữ dựa trên biểu thức, mọi thứ trả về một giá trị. Điều này có thể hơi lạ lúc đầu - Điều gì (FOR i = 1 TO 10 DO (print i))trở lại?

Một số ví dụ đơn giản:

  • (1) trả lại 1
  • (1 + 1) trả lại 2
  • (1 == 1) trả lại TRUE
  • (1 == 2) trả lại FALSE
  • (IF 1 == 1 THEN 10 ELSE 5) trả lại 10
  • (IF 1 == 2 THEN 10 ELSE 5) trả lại 5

Một vài ví dụ phức tạp hơn:

  • Một số thứ, chẳng hạn như một số lời gọi hàm, không thực sự có giá trị có ý nghĩa để trả về (Những thứ chỉ tạo ra tác dụng phụ?). Gọi OpenADoor(), FlushTheToilet()hoặc TwiddleYourThumbs()sẽ trả về một số loại giá trị trần tục, chẳng hạn như OK, Xong hoặc Thành công.
  • Khi nhiều biểu thức không liên kết được ước tính trong một biểu thức lớn hơn, giá trị của điều cuối cùng được đánh giá trong biểu thức lớn sẽ trở thành giá trị của biểu thức lớn. Lấy ví dụ về (FOR i = 1 TO 10 DO (print i)), giá trị của vòng lặp for là "10", nó làm cho (print i)biểu thức được ước tính 10 lần, mỗi lần trả về i dưới dạng một chuỗi. Lần cuối cùng thông qua trả lại 10, câu trả lời cuối cùng của chúng tôi

Nó thường đòi hỏi một sự thay đổi nhỏ về tư duy để tận dụng tối đa ngôn ngữ dựa trên biểu thức, vì thực tế là mọi thứ đều là một biểu thức cho phép 'nội tuyến' rất nhiều thứ

Ví dụ nhanh:

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

là một sự thay thế hoàn toàn hợp lệ cho các biểu thức không dựa trên biểu thức

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

Trong một số trường hợp, bố cục mà mã dựa trên biểu thức cho phép tôi cảm thấy tự nhiên hơn nhiều

Tất nhiên, điều này có thể dẫn đến sự điên rồ. Là một phần của dự án sở thích bằng ngôn ngữ kịch bản dựa trên biểu thức có tên MaxScript, tôi đã xoay sở để đưa ra dòng quái vật này

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
)

2

Một tuyên bố là một trường hợp đặc biệt của một biểu thức, một với void kiểu. Xu hướng của các ngôn ngữ để đối xử với các câu lệnh khác nhau thường gây ra vấn đề, và sẽ tốt hơn nếu chúng được khái quát hóa đúng đắn.

Ví dụ, trong C #, chúng ta có Func<T1, T2, T3, TResult>tập hợp các đại biểu chung quá tải rất hữu ích . Nhưng chúng ta cũng phải có một tương ứngAction<T1, T2, T3> bộ , và lập trình chung có mục đích cao hơn liên tục phải được nhân đôi để đối phó với sự phân chia không may này.

Ví dụ tầm thường - một chức năng kiểm tra xem một tham chiếu có phải là null hay không trước khi gọi đến một chức năng khác:

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

Trình biên dịch có thể đối phó với khả năng TResultvoid? Đúng. Tất cả những gì nó phải làm là yêu cầu trả về được theo sau bởi một biểu thức có kiểu void. Kết quả của default(void)sẽ là loại voidvà func được truyền vào sẽ cần phải có dạng Func<TValue, void>(tương đương với Action<TValue>).

Một số câu trả lời khác ngụ ý rằng bạn không thể xâu chuỗi các câu như bạn có thể với các biểu thức, nhưng tôi không chắc ý tưởng này đến từ đâu. Chúng ta có thể nghĩ về ;cái xuất hiện sau các câu lệnh như là một toán tử infix nhị phân, lấy hai biểu thức kiểu voidvà kết hợp chúng thành một biểu thức kiểu duy nhất void.


Một tuyên bố không phải là một trường hợp đặc biệt của biểu thức. Trong một số ngôn ngữ (tức là hầu hết người kế vị C), nó thực sự là cách khác.
Akangka

2

Báo cáo -> Hướng dẫn theo dõi
Biểu thức tuần tự -> Đánh giá trả về giá trị

Các câu lệnh về cơ bản giống như các bước, hoặc các hướng dẫn trong một thuật toán, kết quả của việc thực hiện một câu lệnh là sự hiện thực hóa của con trỏ lệnh (được gọi là trong trình biên dịch mã)

Biểu thức không ngụ ý và thứ tự thực hiện từ cái nhìn đầu tiên, mục đích của chúng là để đánh giá và trả về một giá trị. Trong các ngôn ngữ lập trình mệnh lệnh, việc đánh giá một biểu thức có một trật tự, nhưng đó chỉ là do mô hình mệnh lệnh, nhưng nó không phải là bản chất của chúng.

Ví dụ về Tuyên bố:

for
goto
return
if

(tất cả đều ngụ ý sự tiến bộ của dòng (câu lệnh) thực thi sang dòng khác)

Ví dụ về biểu thức:

2+2

(nó không ngụ ý ý tưởng thực hiện, nhưng đánh giá)


Còn tác dụng phụ thì sao?
Austin Henley

@AustinHenley không có yêu cầu cho điều đó. Trong thực tế, một biểu hiện chắc chắn có thể có tác dụng phụ.
Akangka

1

Tuyên bố ,

Một tuyên bố là một khối xây dựng theo thủ tục mà từ đó tất cả các chương trình C # được xây dựng. Một câu lệnh có thể khai báo một biến cục bộ hoặc hằng số, gọi một phương thức, tạo một đối tượng hoặc gán một giá trị cho một biến, thuộc tính hoặc trường.

Một loạt các câu lệnh được bao quanh bởi dấu ngoặc nhọn tạo thành một khối mã. Phần thân phương thức là một ví dụ về khối mã.

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

Các câu trong C # thường chứa các biểu thức. Một biểu thức trong C # là một đoạn mã chứa giá trị bằng chữ, tên đơn giản hoặc toán tử và toán hạng của nó.

Biểu hiện ,

Một biểu thức là một đoạn mã có thể được ước tính thành một giá trị, đối tượng, phương thức hoặc không gian tên duy nhất. Hai loại biểu thức đơn giản nhất là chữ và tên đơn giản. Một nghĩa đen là một giá trị không đổi không có tên.

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

Cả i và s đều là các tên đơn giản xác định các biến cục bộ. Khi các biến đó được sử dụng trong một biểu thức, giá trị của biến được lấy và sử dụng cho biểu thức.


Tôi muốn viết if(number >= 0) return true; else return false;hoặc thậm chí tốt hơn bool? IsPositive(int number) { if(number > 0) return true; else if(number < 0) return false; else return null;}:)
Mahdi Tahsildari

1

Tôi thích ý nghĩa của statement logic chính thức của từ này. Đó là một thay đổi trạng thái của một hoặc nhiều biến trong tính toán, cho phép đưa ra tuyên bố đúng hoặc sai về giá trị của chúng.

Tôi đoán sẽ luôn có sự nhầm lẫn trong thế giới điện toán và khoa học nói chung khi thuật ngữ hoặc từ mới được giới thiệu, các từ hiện tại là 'được sử dụng lại' hoặc người dùng không biết gì về thuật ngữ hiện có, được thiết lập hoặc 'phù hợp' cho những gì họ đang mô tả


1

Tôi không thực sự hài lòng với bất kỳ câu trả lời ở đây. Tôi đã xem xét ngữ pháp cho C ++ (ISO 2008) . Tuy nhiên, có thể vì lợi ích của didactics và lập trình, các câu trả lời có thể đủ để phân biệt hai yếu tố (mặc dù thực tế có vẻ phức tạp hơn).

Một câu lệnh bao gồm 0 hoặc nhiều biểu thức, nhưng cũng có thể là các khái niệm ngôn ngữ khác. Đây là hình thức Extended Backus Naur cho ngữ pháp (trích đoạn phát biểu):

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

Chúng ta có thể thấy các khái niệm khác được coi là câu lệnh trong C ++.

  • câu lệnh biểu thức là tự giải thích (một câu lệnh có thể bao gồm từ 0 hoặc nhiều biểu thức, đọc kỹ ngữ pháp, nó khó)
  • caseví dụ như một tuyên bố có nhãn
  • tuyên bố lựa chọnif if/else,case
  • câu lệnh lặpwhile, do...while.for (...)
  • nhảy-tuyên bố s là break, continue, return(có thể trở lại biểu hiện),goto
  • khai báo là tập hợp các khai báo
  • khối thử là câu lệnh đại diện cho try/catchkhối
  • và có thể có thêm một số ngữ pháp

Đây là một đoạn trích cho thấy phần biểu thức:

expression:
        assignment-expression
        expression "," assignment-expression
assignment-expression:
        conditional-expression
        logical-or-expression assignment-operator initializer-clause
        throw-expression
  • biểu thức là hoặc chứa thường xuyên bài tập
  • có điều kiện thể hiện (âm thanh gây hiểu lầm) đề cập đến việc sử dụng của các nhà khai thác ( +, -, *, /, &, |,&& , ||, ...)
  • biểu hiện ném - uh? các throwkhoản là một biểu hiện quá

0

Câu là những câu hoàn chỉnh về mặt ngữ pháp. Biểu hiện là không. Ví dụ

x = 5

đọc là "x được 5." Đây là một câu hoàn chỉnh. Mật mã

(x + 5)/9.0

đọc, "x cộng 5 tất cả chia cho 9.0." Đây không phải là một câu hoàn chỉnh. Tuyên bố

while k < 10: 
    print k
    k += 1

là một câu hoàn chỉnh. Lưu ý rằng tiêu đề vòng lặp là không; "while k <10" là mệnh đề phụ.


whilelà một biểu thức là một số ngôn ngữ như Scala. Bạn đang nhầm lẫn ngữ pháp với gõ. Xem câu trả lời của tôi .
Shelby Moore III

Đây là vòng lặp while trong scala: tutorialspoint.com/scala/scala_while_loop.htm Vòng lặp với vị của nó và không có cơ thể không phải là một câu ngữ pháp hoàn chỉnh. Nó không phải là một biểu thức đầy đủ. Bạn cần cơ thể để hoàn thành nó như một biểu thức.
ncmathsadist

A whilevới một cơ thể vẫn là một biểu hiện trong Scala. Nó cũng có thể là một tuyên bố nếu nó tạo ra các hiệu ứng phụ, điều mà câu trả lời bị đánh giá thấp của tôi cho phép (một biểu thức cũng có thể là một tuyên bố). Câu trả lời của tôi là duy nhất đúng. Xin lỗi tất cả những độc giả không thể hiểu.
Shelby Moore III

Bạn có ý nghĩa gì khi hoàn thành về mặt ngữ pháp? Trong C, (x + 5)/9.0chắc chắn có thể đứng một mình như một tuyên bố. Ngoài ra, nếu hoàn thành về mặt ngữ pháp, bạn có nghĩa là một chương trình hợp lệ, C không cho phép các câu lệnh đứng một mình như một chương trình duy nhất.
Akangka

0

Đây là tóm tắt của một trong những câu trả lời đơn giản nhất mà tôi tìm thấy.

ban đầu được trả lời bởi Anders Kaseorg

Một câu lệnh là một dòng mã hoàn chỉnh thực hiện một số hành động, trong khi một biểu thức là bất kỳ phần nào của mã đánh giá thành một giá trị.

Các biểu thức có thể được kết hợp giữa các chiều theo chiều ngang thành các biểu thức lớn hơn bằng cách sử dụng các toán tử, trong khi các câu lệnh chỉ có thể được kết hợp giữa các chiều dọc theo chiều dọc bằng cách viết lần lượt hoặc bằng các cấu trúc khối.

Mọi biểu thức có thể được sử dụng như một câu lệnh (có tác dụng là đánh giá biểu thức và bỏ qua giá trị kết quả), nhưng hầu hết các câu lệnh không thể được sử dụng làm biểu thức.

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


0

Cơ sở thực tế của các khái niệm này là:

Biểu thức : Một thể loại cú pháp có thể được đánh giá thành một giá trị.

Tuyên bố : Một loại cú pháp có thể hiện có thể liên quan đến các đánh giá của một biểu thức và giá trị kết quả của đánh giá (nếu có) không được đảm bảo.

Bên cạnh bối cảnh ban đầu của FORTRAN trong những thập niên đầu, cả hai định nghĩa về biểu thức và phát biểu trong câu trả lời được chấp nhận rõ ràng là sai:

  • Biểu thức có thể là toán hạng không được định giá. Các giá trị không bao giờ được sản xuất từ ​​chúng.
    • Subexpression trong đánh giá không nghiêm ngặt có thể chắc chắn không được đánh giá.
      • Hầu hết các ngôn ngữ giống như C có các quy tắc đánh giá ngắn mạch được gọi là điều kiện bỏ qua một số điều kiện đánh giá phụ không thay đổi kết quả cuối cùng bất chấp các tác dụng phụ.
    • C và một số ngôn ngữ giống như C có khái niệm toán hạng không được đánh giá có thể được định nghĩa chuẩn trong đặc tả ngôn ngữ. Các cấu trúc như vậy được sử dụng để tránh các đánh giá chắc chắn, do đó thông tin ngữ cảnh còn lại (ví dụ: các loại hoặc yêu cầu căn chỉnh) có thể được phân biệt tĩnh mà không thay đổi hành vi sau khi dịch chương trình.
      • Ví dụ, một biểu thức được sử dụng làm toán hạng của sizeoftoán tử không bao giờ được đánh giá.
  • Báo cáo không có gì để làm với các cấu trúc dòng. Họ có thể làm một cái gì đó nhiều hơn các biểu thức, tùy thuộc vào thông số kỹ thuật ngôn ngữ.
    • Fortran hiện đại, là hậu duệ trực tiếp của FORTRAN cũ, có các khái niệm về câu lệnh thực thi s và câu lệnh không thể thực hiện được s.
    • Tương tự, C ++ định nghĩa khai báo là danh mục con cấp cao nhất của đơn vị dịch thuật. Một tuyên bố trong C ++ là một tuyên bố. (Điều này không đúng trong C.) Cũng có những câu lệnh biểu thức giống như câu lệnh thực thi của Fortran.
    • Đối với lợi ích của việc so sánh với các biểu thức, chỉ có các câu lệnh "thực thi". Nhưng bạn không thể bỏ qua thực tế là các câu lệnh đã được khái quát hóa thành các cấu trúc tạo thành các đơn vị dịch thuật trong các ngôn ngữ bắt buộc như vậy. Vì vậy, như bạn có thể thấy, các định nghĩa của thể loại khác nhau rất nhiều. Tài sản chung duy nhất (có lẽ) vẫn được bảo tồn trong số các ngôn ngữ này là các câu lệnh dự kiến ​​sẽ được diễn giải theo thứ tự từ vựng (đối với hầu hết người dùng, từ trái sang phải và từ trên xuống dưới).

(BTW, tôi muốn thêm [cần dẫn nguồn] vào câu trả lời liên quan đến các tài liệu về C vì tôi không thể nhớ liệu DMR có ý kiến ​​như vậy hay không. Có vẻ như không có lý do gì để duy trì sự trùng lặp chức năng trong thiết kế của C : đáng chú ý là toán tử dấu phẩy so với các câu lệnh.)

(Lý do sau đây không phải là câu trả lời trực tiếp cho câu hỏi ban đầu, nhưng tôi cảm thấy cần phải làm rõ điều gì đó đã được trả lời ở đây.)

Tuy nhiên, điều đáng nghi ngờ là chúng ta cần một loại "tuyên bố" cụ thể trong các ngôn ngữ lập trình có mục đích chung:

  • Các câu lệnh không được đảm bảo có nhiều khả năng ngữ nghĩa hơn các biểu thức trong các thiết kế thông thường.
    • Nhiều ngôn ngữ đã từ bỏ thành công khái niệm tuyên bố để có được thiết kế tổng thể sạch sẽ, gọn gàng và nhất quán.
      • Trong các ngôn ngữ như vậy, các biểu thức có thể thực hiện mọi thứ mà các câu lệnh kiểu cũ có thể làm: chỉ cần loại bỏ các kết quả không sử dụng khi các biểu thức được ước tính, bằng cách để các kết quả không được chỉ định rõ ràng (ví dụ trong R n RS Scheme) hoặc có một giá trị đặc biệt (như một giá trị của một loại đơn vị) không thể sản xuất từ ​​các đánh giá biểu thức bình thường.
      • Các quy tắc đánh giá thứ tự từ vựng của các biểu thức có thể được thay thế bằng toán tử điều khiển trình tự rõ ràng (ví dụ begintrong Lược đồ) hoặc đường cú pháp của các cấu trúc đơn âm.
      • Các quy tắc trật tự từ vựng của các loại "tuyên bố" khác có thể được lấy từ các phần mở rộng cú pháp (ví dụ sử dụng macro vệ sinh) để có được chức năng cú pháp tương tự. (Và nó thực sự có thể làm nhiều hơn nữa .)
    • Ngược lại, các tuyên bố không thể có các quy tắc thông thường như vậy, bởi vì chúng không bao gồm việc đánh giá: không có khái niệm chung nào về "đánh giá thay thế". (Ngay cả nếu có, tôi nghi ngờ có thể có một cái gì đó nhiều hơn là sao chép và dán từ các quy tắc đánh giá biểu thức tồn tại.)
      • Thông thường, các ngôn ngữ bảo tồn các câu lệnh cũng sẽ có các biểu thức để diễn đạt các tính toán và có một thể loại con cấp cao nhất của các câu lệnh được bảo tồn cho các đánh giá biểu thức cho thể loại con đó. Ví dụ, C ++ có cái gọi là câu lệnh biểu thức như là thể loại con và sử dụng các quy tắc đánh giá biểu thức giá trị bị loại bỏ để chỉ định các trường hợp chung của các đánh giá biểu thức đầy đủ trong ngữ cảnh đó. Một số ngôn ngữ như C # chọn tinh chỉnh các bối cảnh để đơn giản hóa các trường hợp sử dụng, nhưng nó làm mờ thông số kỹ thuật nhiều hơn.
  • Đối với người dùng ngôn ngữ lập trình, tầm quan trọng của câu lệnh có thể khiến họ nhầm lẫn thêm.
    • Việc tách các quy tắc biểu thức và phát biểu trong các ngôn ngữ đòi hỏi nhiều nỗ lực hơn để học một ngôn ngữ.
    • Việc giải thích trật tự từ vựng ngây thơ ẩn giấu khái niệm quan trọng hơn: đánh giá biểu thức. (Điều này có lẽ là vấn đề nhất trên tất cả.)
      • Ngay cả các đánh giá của các biểu thức đầy đủ trong các câu lệnh là ràng buộc với thứ tự từ vựng, các biểu thức con cũng không (nhất thiết). Người dùng cuối cùng nên tìm hiểu điều này bên cạnh bất kỳ quy tắc nào được kết hợp với các tuyên bố. (Xem xét làm thế nào để một người mới nhận được điểm ++i + ++ivô nghĩa trong C.)
      • Một số ngôn ngữ như Java và C # ràng buộc thêm thứ tự các đánh giá của các biểu hiện con được cho phép không biết các quy tắc đánh giá. Nó có thể còn nhiều vấn đề hơn.
        • Điều này dường như quá cụ thể đối với người dùng đã học được ý tưởng đánh giá biểu thức. Nó cũng khuyến khích cộng đồng người dùng theo mô hình tinh thần mờ nhạt của thiết kế ngôn ngữ.
        • Nó nở đặc tả ngôn ngữ thậm chí nhiều hơn.
        • Nó có hại cho việc tối ưu hóa bằng cách thiếu tính biểu cảm của chủ nghĩa không điều kiện trong các đánh giá, trước khi các nguyên thủy phức tạp hơn được đưa ra.
      • Một vài ngôn ngữ như C ++ (đặc biệt là C ++ 17) chỉ định bối cảnh tinh tế hơn của các quy tắc đánh giá, như một sự thỏa hiệp của các vấn đề ở trên.
        • Nó nở đặc tả ngôn ngữ rất nhiều.
        • Điều này hoàn toàn đi ngược lại với sự đơn giản cho người dùng trung bình ...

Vậy tại sao lại tuyên bố? Dù sao, lịch sử đã là một mớ hỗn độn. Có vẻ như hầu hết các nhà thiết kế ngôn ngữ không cẩn thận lựa chọn của họ.

Tồi tệ hơn, nó thậm chí còn cung cấp cho một số người đam mê hệ thống loại (không đủ quen thuộc với lịch sử PL) một số quan niệm sai lầm rằng hệ thống loại phải có những điều quan trọng phải làm với các thiết kế quy tắc thiết yếu hơn về ngữ nghĩa hoạt động.

Nghiêm túc mà nói, lý luận tùy thuộc vào các loại không phải là xấu trong nhiều trường hợp, nhưng đặc biệt không mang tính xây dựng trong trường hợp đặc biệt này. Ngay cả các chuyên gia có thể làm hỏng mọi thứ lên.

Ví dụ, một người nào đó nhấn mạnh bản chất đánh máy tốt là đối số trung tâm chống lại cách đối xử truyền thống của các phần tiếp theo không bị giới hạn . Mặc dù kết luận có phần hợp lý và những hiểu biết về các hàm tổng hợp vẫn ổn ( nhưng vẫn còn quá ngây thơ đối với bản chất ), nhưng lập luận này không đúng vì nó hoàn toàn bỏ qua cách tiếp cận "kênh bên" trong thực tế như _Noreturn any_of_returnable_types(trong C11) để mã hóa Falsum. Và nói đúng ra, một cỗ máy trừu tượng với trạng thái không thể đoán trước không giống với "một chiếc máy tính bị sập".


0

Trong ngôn ngữ lập trình hướng câu lệnh, khối mã được định nghĩa là danh sách các câu lệnh. Nói cách khác, một câu lệnh là một phần cú pháp mà bạn có thể đặt bên trong một khối mã mà không gây ra lỗi cú pháp.

Wikipedia định nghĩa từ tương tự

Trong lập trình máy tính, một câu lệnh là một đơn vị cú pháp của một ngôn ngữ lập trình mệnh lệnh thể hiện một số hành động sẽ được thực hiện. Một chương trình được viết bằng ngôn ngữ như vậy được hình thành bởi một chuỗi gồm một hoặc nhiều câu lệnh

Lưu ý các tuyên bố sau. (mặc dù "một chương trình" trong trường hợp này là sai về mặt kỹ thuật vì cả C và Java đều từ chối một chương trình không chứa gì các câu lệnh.)

Wikipedia định nghĩa biểu thức từ là

Một biểu thức trong ngôn ngữ lập trình là một thực thể cú pháp có thể được đánh giá để xác định giá trị của nó

Tuy nhiên, điều này là sai, bởi vì trong Kotlin, throw new Exception("")là một biểu thức nhưng khi được đánh giá, nó chỉ đơn giản là ném một ngoại lệ, không bao giờ trả lại bất kỳ giá trị nào.

Trong một ngôn ngữ lập trình gõ tĩnh, mỗi biểu thức có một loại. Định nghĩa này, tuy nhiên, không hoạt động trong một ngôn ngữ lập trình được gõ động.

Cá nhân, tôi định nghĩa một biểu thức là một phần cú pháp có thể được soạn thảo bằng một toán tử hoặc hàm gọi để mang lại một biểu thức lớn hơn. Điều này thực sự giống với giải thích về biểu thức của Wikipedia:

Nó là sự kết hợp của một hoặc nhiều hằng số, biến, hàm và toán tử mà ngôn ngữ lập trình diễn giải (theo các quy tắc ưu tiên và liên kết cụ thể của nó) và tính toán để tạo ra ("trả về", trong một môi trường có trạng thái)

Nhưng, vấn đề là ở ngôn ngữ lập trình C, được cung cấp một hàm thực thi Một cái gì đó như thế này:

void executeSomething(void){
    return;
}

executeSomething()một biểu thức hay nó là một tuyên bố? Theo định nghĩa của tôi, đó là một tuyên bố vì như được định nghĩa trong ngữ pháp tham chiếu C của Microsoft,

Bạn không thể sử dụng giá trị (không tồn tại) của một biểu thức có kiểu void theo bất kỳ cách nào, bạn cũng không thể chuyển đổi một biểu thức void (bằng cách chuyển đổi ngầm định hoặc rõ ràng) thành bất kỳ loại nào ngoại trừ void

Nhưng cùng một trang chỉ rõ rằng cú pháp như vậy là một biểu thức.


-6

Để cải thiện và xác nhận câu trả lời trước của tôi, các định nghĩa về thuật ngữ ngôn ngữ lập trình nên được giải thích từ lý thuyết loại khoa học máy tính khi áp dụng.

Một biểu thức có một loại khác với loại Dưới cùng, tức là nó có một giá trị. Một tuyên bố có loại Đơn vị hoặc Dưới cùng.

Từ đó, một tuyên bố chỉ có thể có bất kỳ hiệu ứng nào trong chương trình khi nó tạo ra hiệu ứng phụ, bởi vì nó không thể trả về một giá trị hoặc nó chỉ trả về giá trị của loại Đơn vị không thể gán được (trong một số ngôn ngữ như một C void) hoặc (chẳng hạn như trong Scala) có thể được lưu trữ để đánh giá chậm trễ của tuyên bố.

Rõ ràng a @pragmahoặc a /*comment*/không có loại và do đó được phân biệt với các câu lệnh. Do đó, loại tuyên bố duy nhất không có tác dụng phụ sẽ là không hoạt động. Không hoạt động chỉ hữu ích như một trình giữ chỗ cho các tác dụng phụ trong tương lai. Bất kỳ hành động nào khác do tuyên bố sẽ là một tác dụng phụ. Một lần nữa một gợi ý trình biên dịch, ví dụ @pragma, không phải là một câu lệnh vì nó không có kiểu.


2
Sự phân biệt không có gì để làm với các loại biểu thức. Các câu lệnh được định nghĩa cú pháp không có loại nào trong nhiều ngôn ngữ. Mặc dù tôi không chống lại việc gán một loại theo các thuật ngữ như vậy trong lý thuyết, các phương pháp điều trị khác nhau trên @pragmahoặc /*comment*/không nhất quán về mặt logic.
FrankHB

-11

Chính xác nhất, một câu lệnh phải có "tác dụng phụ" (nghĩa là bắt buộc ) và một biểu thức phải một loại giá trị (nghĩa là không phải là loại dưới cùng).

Các loại một tuyên bố là loại đơn vị, nhưng do Tạm dừng lý đơn vị là hư cấu để cho phép nói các loại đáy .


Voidkhông chính xác là loại dưới cùng (nó không phải là kiểu con của tất cả các loại có thể). Nó tồn tại trong các ngôn ngữ không có hệ thống âm thanh hoàn toàn . Điều đó nghe có vẻ giống như một tuyên bố hợm hĩnh, nhưng tính đầy đủ như chú thích phương sai rất quan trọng để viết phần mềm mở rộng.

Hãy xem Wikipedia nói gì về vấn đề này.

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

Trong lập trình máy tính, một câu lệnh là phần tử độc lập nhỏ nhất của ngôn ngữ lập trình mệnh lệnh thể hiện một số hành động cần thực hiện.

Nhiều ngôn ngữ (ví dụ C) tạo ra sự khác biệt giữa các câu lệnh và định nghĩa, với một câu lệnh chỉ chứa mã thực thi và một định nghĩa khai báo một mã định danh, trong khi một biểu thức chỉ đánh giá một giá trị.


5
Một tuyên bố không cần phải có tác dụng phụ. Ví dụ, trong python passlà một tuyên bố. Nó là không có, và nó không đánh giá bất cứ điều gì.
Matthew Schinckel

9
-1 Điều này là sai. Một tuyên bố không phải tác dụng phụ. Xem phần 1.5 của Đặc tả ngôn ngữ C # . Nó không chỉ không xác định rằng các câu lệnh phải có tác dụng phụ, mà nó còn liệt kê một số câu lệnh có thể không có tác dụng phụ.
NullUserException

2
@NullUserException Tôi đọc phần đó. Các câu lệnh Khai báo, Biểu thức, Lựa chọn, Lặp lại và Nhảy đều có thể tạo ra các hiệu ứng phụ. Nhưng nếu có một biểu thức RT, thì đó không phải là một tuyên bố. Tôi nhận ra đặc tả này là đánh đồng các biểu thức với các câu lệnh, nhưng câu hỏi này yêu cầu sự khác biệt giữa chúng. Vì vậy, hoặc câu hỏi không có câu trả lời, hoặc bạn đang sử dụng thông số C # theo đúng nghĩa đen. Câu trả lời được bình chọn hàng đầu là cố gắng nói những gì tôi đã làm. Nhưng "làm một cái gì đó" là vô nghĩa. "Tác dụng phụ" là cách có ý nghĩa để nói "làm điều gì đó". Chúng ta phải suy nghĩ, không chỉ hồi sinh.
Shelby Moore III

13
@ShelbyMooreIII Bạn nói đúng. Các tài liệu chính thức là sai . Marc Gravell và Jon Skeet, những người có thể là những người đăng C # đáng kính nhất hoạt động trên SO ngoài Eric Lippert, đã sai . Tôi và tất cả những người khác đã đánh giá thấp bạn và để lại bình luận giải thích vị trí của chúng tôi là sai . Bạn đúng rồi. Bạn rõ ràng là người duy nhất biết họ đang nói về điều gì, vì bạn thông minh hơn tất cả những người còn lại của SO.
NullUserException

3
Biết định nghĩa chính xác của các khái niệm như tuyên bố, biểu thức, diễn viên, chuyển đổi, vv không có tác động đến 99,999% các nhiệm vụ lập trình hàng ngày. Hãy nghĩ về điều đó . Ngoài ra: hầu hết mọi người không quan tâm đến Haskell và Scala.
NullUserException
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.