Comment ký tự đặc biệt toán tử trong ruby năm 2024

Khá là khó để viết những điểm chính hình dung sự khác biệt khi chuyển từ C và C++ qua Ruby vì thật sự là có sự khác biệt rất lớn. Ruby runtime đảm nhận nhiều nhiệm vụ là một lý do. Ruby có vẻ xa vời với nguyên tắc “không có cơ chế ẩn” của C- điểm này của Ruby giúp cho công việc của chúng ta trở nên dễ dàng hơn bằng việc đánh đổi thêm một ít thời gian khi thực thi. Trừ khi bạn muốn tối ưu mã của mình, bạn không cần quan tâm về việc “giữ cho trình biên dịch thực thi dễ dàng” khi sử dụng Ruby.

Việc đó nói lên một điều là thời gian thực thi của Ruby sẽ chậm hơn C và C++. Trong cùng một thời điểm, thì bạn sẽ thấy thời gian viết code và chạy thử với Ruby sẽ nhanh như thế nào khi bạn chỉ cần viết một vài dòng code. Ruby đơn giản hơn C++ rất nhiều.

Ruby là ngôn ngữ động, chứ không phải kiểu tĩnh - phải thực hiện rất nhiều việc khi thực thi. Ví dụ, bạn không cần biết Ruby sẽ liên kết đến mô-đun nào [chỉ cần load và dùng] hoặc gọi phương thức nào.

May mắn là Ruby và C có mối quan hệ cộng sinh. Ruby hỗ trợ cái gọi là “mô-đun mở rộng”. Có những mô-đun mà bạn có thể sử dụng trong Ruby [và những thành phần nào mà từ bên ngoài có thể xem xét và thực thi như các mô-đun khác của Ruby], nhưng nó được viết bằng C. Bằng cách này, bạn có thể chỉa những phần xử lý quan trọng của Ruby xuống để xử lý bằng C.

Cấu trúc điều khiển [Control Structure] là một trong các đặc trưng cơ bản của phương pháp lập trình cấu trúc. Trong đó, người ta sử dụng 3 cấu trúc điều khiển để tạo nên logic của chương trình. Mọi vấn đề về logic đều được giải quyết bằng cách phối hợp 3 cấu trúc: Cấu trúc tuần tự [Sequence structures], Cấu trúc chọn [Selection structures] và cấu trúc lặp [Iterative structures].

Trong đề tài này, ta phân biệt hai loại điều khiển: Loại thứ nhất là điều khiển thứ tự thực thi của các tác vụ trong một kết hợp, gọi là điều khiển trình tự [sequence control]. Loại thứ hai là điều khiển việc truy xuất dữ liệu ở mỗi tác vụ và việc truyền dữ liệu giữa các tác vụ trong một kết hợp, gọi là điều khiển dữ liệu [data control].

NỘI DUNG BÀI VIẾT

Giới thiệu

I Điều khiển trình tự

  • Cấu trúc điều khiển trình tự trong biểu thức
  • Điều khiển trong biểu thức [Control within expressions]
  • Các cấu trúc điều khiển trình tự giữa các phát biểu
  • Các câu lệnh lựa chọn [Selection Statements]
  • Các câu lệnh lặp [Iterative Statements]
  • Rẽ nhánh không điều kiện [Unconditional Branching]
  • Cấu trúc điều khiển trình tự giữa các chương trình con
  • Cấu trúc gọi đệ quy [Recursive Call]

II Điều khiển dữ liệu

Tóm tắt

Tài liệu tham khảo

\========================

Giới thiệu

Dữ liệu và tác vụ là hai yếu tố cơ bản của chương trình. Mỗi sự kết hợp của chúng gắn liền với cấu trúc điều khiển. Cấu trúc điều khiển là tập hợp các qui tắc xác định thứ tự thực hiện chương trình.

– Xét về cấu trúc, có 3 loại điều khiển:

+ Điều khiển trong các biểu thức. + Điều khiển giữa các phát biểu: cấu trúc điều kiện/ cấu trúc lặp. + Điều khiển trong chương trình con: gọi trả về hay đệ qui.

– Xét về thiết kế ngôn ngữ, có 2 loại điều khiển:

+ Điều khiển ngầm: được thiết kế trong ngôn ngữ lập trình. [Ví dụ: quy tắc ưu tiên các toán tử]

+ Điều khiển tường minh: được xác định bởi lập trình viên. [Ví dụ: phát biểu GOTO, CONTINUE, BEAK,…]

Các vấn đề logic được giải quyết bằng cách phối hợp 3 cấu trúc:

– Cấu trúc tuần tự [Sequence structures]. – Cấu trúc chọn [Selection structures]. – Cấu trúc lặp [Iterative structures].

[True: T / False: F]

– Lệnh [statement]: một biểu thức kết thúc bởi 1 dấu chấm phẩy gọi là 1 lệnh.

vd: int a, b, c; a=10;

– Khối lệnh [block]: một hay nhiều lệnh được bao quanh bởi cặp dấu { } gọi là một khối lệnh. Về mặt cú pháp, khối lệnh tương đương 1 câu lệnh đơn.

if[a=], từ trái sang phải. + Đánh giá toán tử logic NOT, trái sang phải. + Đánh giá toán tử logic AND, trái sang phải. + Đánh giá toán tử logic XOR, trái sang phải. + Đánh giá toán tử logic OR, trái sang phải.

Hiệu ứng lề

Hiệu ứng lề là một phép toán làm thay đổi giá trị của đối tượng dữ liệu được tham khảo đến các phép toán khác trong biểu thức.

Hàm hiệu ứng lề là hàm thay đổi biến không cục bộ hoặc có truyền quy chiếu.

int a=5; int fun1[] { a = 17; return  3; } void fun2[] { a = a + fun1[]; } void main[] { fun2[]; } Kết quả có được của a là 8 hay 20? Với ngôn ngữ C trả về giá trị của a là 20.

Giải pháp giải quyết hiệu ứng lề:

+ Ngôn ngữ lập trình không cho phép hàm tham chiếu các biến không cục bộ và truyền quy chiếu. Giải pháp này dễ thực hiện nhưng không linh hoạt.

+ Ngôn ngữ lập trình phải quy định thứ tự ưu tiên của các toán hnag5. Hạn chế, làm giảm khả năng tối ưu code của trình biên dịch.

Ví dụ hiệu ứng lề với biểu thức A * FUNC[X] + A được biểu diễn bởi cấu trúc cây như sau:

Nếu thực hiện FUNC[X] không ảnh hưởng gì đến giá trị của A thì kết quả của việc tính biểu thức trên không phụ thuộc vào việc tham khảo giá trị của A [A+] trước hay thực hiện phép nhân trước [khi thực hiện phép cộng], cũng như không phụ thuộc vào việc tham khảo giá trị của A [A*] trước hay thực hiện FUNC[X] trước [khi thực hiện phép nhân]. Nhưng sẽ hoàn toàn khác nếu việc thực hiện FUNC[X] làm thay đổi giá trị của A, sau khi FUNC[X] được thực hiện xong.

Cú pháp của biểu thức

– Dạng trung tố [infex]: ký hiệu phép toán được viết giữa 2 toán hạng. Ví dụ: [A + B] * [C – A]

– Dạng tiền tố [prefix]: ký hiệu phép toán được viết trước các toán hạng. Ví dụ: * [+ [A B] ] – [C A]]

– Dạng hậu tố [posfix]: ký hiệu phép toán được viết sau các toán hạng Ví dụ: [[A B] +] [C A] -]*

\===================================

Các câu lệnh lựa chọn

[Selection Statements]

Trong cuộc sống hằng ngày, hẳn bạn cũng đã từng chọn lựa, đưa ra quyết định nào đó. Lấy ví dụ, nếu bạn có 10.000 vnđ, bạn sẽ mua một hủ yaourt và một cây chupa chups. Thêm một ví dụ, khi tham gia chơi cờ tướng, mỗi quân cờ ta lựa chọn, bắt buộc phải đi nước cờ tương ứng đã quy định [Tốt chỉ đi 1 ô, Mã đi ngang 2 ô,…]. Cấu trúc if, switch-case về mặt ý nghĩa tương tự như các ví dụ trên, đối với ngôn ngữ lập trình, việc lựa chọn, xác định là yếu tố quan trọng không thể thiếu trong một chương trình hoàn thiện.

Một câu lệnh lựa chọn cung cấp các lựa chọn giữa hai hay nhiều cách thực thi trong một chương trình. Lệnh lựa chọn [lệnh điều khiển] là một lệnh biểu thị sự lựa chọn của hai hoặc đa nhánh để thực hiện.

Chia làm 2 loại:

+ Chỉ có 2 lựa chọn [lệnh if]. + Nhiều lựa chọn [lệnh case].

“Các câu lệnh lựa chọn” là cầu trúc được trình bày đầu tiên trong cấu trúc điều khiển trình tự giữa các phát biểu, sau đó chúng ta sẽ tìm hiểu và phân tích “các câu lệnh lặp” và phần cuối cùng là “rẽ nhánh không điều kiện”.

1 Cấu trúc lệnh điều khiển IF … ELSE – [Two-Way Selection Statements]

– Dạng phổ biến:

if control_expression then clause else clause

– Các yếu tố trong lệnh 2 lựa chọn:

+ Dạng và kiểu của biểu thức lựa chọn như thế nào, quan hệ, toán và logic? + Các câu lệnh theo sau then và else? + Lệnh lựa chọn có lồng nhau hay không?

  1. Dạng và kiểu của biểu thức

– Cấu trúc if ở dạng 1.1 cho thấy nếu biểu thức điều kiện có giá trị “true” thì statement được thực hiện, ngược lại không làm gì cả. Tại dạng 1.2 nếu biểu thức có giá trị “true” thì statement 1 được thực hiện, ngược lại statement 2 được thực hiện.

– ALGOL 60: Chỉ dùng biểu thức logic if[boolean_expression] then statement else statement

– C [89 trở về trước]: Chỉ dùng biểu thức logic. – C [99] và C++: biểu thức toán và logic [vd: if [a-b] printf[“OK”] else printf [“Yes”]] – Ada, Java và C# chỉ dùng biểu thức logic.

  1. Sự lựa chọn lồng nhau

– Ví dụ 1b, đoạn chương trình java:

if[sum ==0] if[count ==0] // Lệnh if nào sẽ đi cùng với lệnh else?

    result=0;  
else result =1; Ngôn ngữ C, C++, C#, Java quy định lệnh if và lệnh else gần nhau nhất sẽ đi cùng nhau.

Ví dụ 2b: Đoạn chương trình bên dưới viết lệnh else thẳng hàng với if[n>0], nhưng lệnh else ở đây được hiểu đi kèm với if[a>b] vì nó nằm gần với if[a>b] nhất và if[a>b] chưa có else. Do đó để giảm và tránh nhầm lẫn ta sẽ viết thẳng hàng if[a>b] với else hoặc có thể đặt if[a>b] x=a vào trong khối lệnh {}.

... if[n > 0]

if[a > b]   
x=a; else x=b; Perl yêu cầu lệnh ghép [if else đầy đủ], dùng 2 ngoặc nhọn {} để phân định.

if[sum == 0]{

  if[count == 0]{  
        result=0;  
    }  
} else { result=1; } khác với

if[sum == 0]{

  if[count == 0]{  
        result=0;  
    }  
else { result=1; } } Cấu trúc if lồng nhau càng nhiều, cấp độ phức tạp càng cao, chương trình chạy càng chậm và trong lúc lập trình dễ bị nhầm lẫn.

2 Lệnh lựa chọn đa nhánh – [Multiple-Selection Statements]

Cho phép lựa chọn 1 nhánh trong số nhiều nhánh lệnh để thực hiện. Các yếu tố trong lệnh lựa chọn đa nhánh:

+ Kiểu và dạng của biểu thức điều khiển? + Công việc của từng nhánh lệnh? + Có nhánh lệnh nào không thỏa điều kiện? Nếu có nó thực hiện lệnh gì?

  1. Mô hình switch-case

switch [expression]{ case constant_expression1 : statement1 ; break; … case constant_expressionn : statement_n; break; [default: statementn+1] }

Tương ứng với từng giá trị của expression mà statementi được thực hiện. Trong trường hợp giá trị biểu thức không trùng với giá trị nào thì statementn+1 được thực hiện.

Chú ý:

+ expression trong switch[ ] phải có kiểu dữ liệu đếm được như char, int,.. không thể là kiểu thực [double, float].

+ Sau mỗi statement phải có lệnh break, nếu không thì các statement lần lượt được thực thi cho đến khi gặp 1 lệnh break khác.

– Switch-case trong C, C++, Java:

+ Biểu thức điều khiển phải là kiểu nguyên. + Câu lệnh lựa chọn có thể là 1 câu lệnh đơn hoặc khối lệnh. + Kết thúc cấu trúc switch-case khi gặp break; + Default: được chọn nếu không có giá trị nào thỏa expression.

Ví dụ:

– Switch-case trong Ada:

case expression is when choice list => stmt_sequence; … when choice list => stmt_sequence; when others => stmt_sequence; end case;

Giá trị tương ứng với một giá trị duy nhất [ví dụ 5], một phạm vi [ 1 .. 20] hoặc kết hợp các miền giá trị, ngăn cách bởi ký tự ‘|’.

Ví dụ:

– Switch-case trong C#:

Biểu thức trong switch[] có giá trị đếm được, kiểu dữ liệu là một số nguyên , ký tự, chuỗi ký tự hoặc kiểu dữ liệu liệt kê [enum]. Ta có thể thay lệnh break thành goto hoặc continue.

Ta có ví dụ sau:

  1. Mô hình if

Trong nhiều trường hợp, khi sử dụng lệnh switch-case sẽ không phù hợp với đa lựa chọn [ngoại trừ Ruby]. Một ví dụ, khi thực hiện việc chọn lựa dựa trên một biểu thức Boolean [đúng hoặc sai] ta sử dụng cấu trúc if else lồng nhau để mô phỏng như một lệnh lựa chọn đa nhánh [case].

Lệnh lựa chọn đa nhánh có thể chuyển thành lệnh chọn 2 nhánh với else-if

if [expr == const_expr_1] stmt_1; else if [expr == const_expr_2] stmt_2; … else if [expr == const_expr_n] stmt_n; else stmt_n+1;

Ví dụ trong Python [trong Python else-if được viết thành elif ]:

\===================================

Các câu lệnh lặp

[Iterative Statements]

Mỗi ngày bạn đánh răng ít nhất 2 lần, học một môn học mỗi tuần 2 tiết, rửa chén đến khi sạch, đi bộ [chân trái, chân phải, rồi lại chân trái chân phải,…], có rất rất nhiều hoạt động thường nhật xảy ra lặp đi lặp lại. Trong ngôn ngữ lập trình cũng vậy, đôi lúc chúng ta viết một đoạn code lặp đi lặp lại nhiều lần để thực hiện một yêu cầu nào đó, thật vất vả khi bạn phải viết 100 câu lệnh giống nhau chỉ để làm một công việc. Chính vì vậy, khái niệm lệnh lặp giúp rất nhiều cho lập trình viên để xây dựng các chương trình khác nhau một cách hiệu quả, nhanh chóng.

Ở phần này, chúng ta sẽ chú ý đến ba cấu trúc: for, while, do-while. Ba cấu trúc này đóng góp rất lớn trong quá trình cài đặt phần mềm, loại bỏ nhanh chóng việc giảm hiệu xuất gây ra do sử dụng quá nhiều dòng lệnh có chung tính chất.

– Điều kiện kết thúc sự lặp có thể được xác định thông qua biến đếm hoặc là điều kiện phức tạp được biểu diễn bằng một biểu thức luận lý. Có 2 loại lệnh lặp: Lệnh lặp với bộ đếm và lệnh lặp có điều kiện.

– Các yếu tố trong lệnh lặp

+ Làm thế nào để kiểm soát lặp? + Kiểm soát lặp xuất hiện ở đâu trong vòng lặp?

Lệnh lặp với bộ đếm – [Counter-Controlled Loops]

Trong lệnh điều khiển lặp có một biến số, ta gọi đây là biến lặp. Trong đó giá trị của biến đếm từ giá trị bắt đầu [initial] đến giá trị kết thúc [terminal] và giá trị của bước nhảy [stepsize]

– Các yếu tố trong lệnh lặp:

+ Kiểu của biến lặp và phạm vi? + Giá trị của biến lặp khi vòng lặp kết thúc? + Giá trị của biến lặp có được thay đổi trong thân vòng lặp không? Nếu có thì có ảnh hưởng đến vòng lặp không?

– Cú pháp Fortran 90:

+ do bien_lap = gia_tri_dau, gia_tri_ket_thuc [, buoc_nhay] + Trị của bước nhảy là bất kỳ [trừ 0], mặc định là 1 + gia_tri_dau, gia_tri_ket_thuc có thể là biểu thức + Kiểu biến lặp phải là kiểu nguyên. + Biến lặp không được thay đổi trong thân vòng lặp.

– Cú pháp Fortran 95:

do bien_lap = gia_tri_dau, gia_tri_ket_thuc [, buoc_nhay] … end do

– Cú pháp lệnh for của Pascal

for bien_lap := bat_dau [to | downto] ket_thuc do …

+ bien_lap có kiểu số nguyên, giá trị không thay đổi trong thân vòng lặp. + Sau khi kết thúc vòng lặp, giá trị của bien_lap không xác định.

+ bat_dau, ket_thuc có thể là biểu thức, nhưng các tham số có thể thay đổi trong vòng lặp và không ảnh hường đến vòng lặp.

Ta có ví dụ phát biểu for:

for I:=E1 to E2 do S

Phát biểu lặp này ta có thể thay thế bằng phát biểu GOTO và phát biểu điều kiện như sau:

I:=E1; L0: if I > E2 then goto L1 S:I:=I+1; goto L0 L1: …

– Cú pháp lệnh for của Ada:

for bien_lap in [reverse] day_roi_rac loop … end loop

+ day_roi_rac: miền con số nguyên, 1…10, hoặc kiểu liệt kê monday…Friday + Phạm vi của biến có bao gồm vòng lặp. + Giá trị của biến lặp không xác định khi vòng lặp kết thúc.

– Cú pháp lệnh for trong C:

for [[expr_1] ; [expr_2]; [expr_3]] statement

+ Mọi thứ có thể thay đổi trong thân vòng lặp. + Biểu thức expr_1 được định lượng 1 lần trước khi tực hiện vòng lặp [ biểu thức khởi tạo].

+ Sau mỗi lần lặp, expr_2 [biểu thức điều kiện] và expr_3 [biểu thức điều khiển lặp] được định lượng. + Xóa các biểu thức expr_1, expr_2, expr_3 trong vòng for sẽ cho vòng lặp vô tận. + C++ cho phép khai báo kiểu trong expr_1

for [int count=0;count Nhận định qua 2 loại lệnh lặp: Các phát biểu lặp vẫn được hiện thực bằng các lệnh nhảy có điều kiện và không điều kiện của ngôn ngữ máy.

\===================================

Rẽ nhánh không điều kiện

[Unconditional Branching]

– Lệnh rẽ nhánh không điều kiện được đưa ra vào những năm cuối thập niên 60. – Cho phép thay đổi thứ tự thực hiện chương trình. – Cơ chế phổ biến nhất là lệnh: goto – Một số NNLT không hỗ trợ lệnh goto – C# cung cấp lệnh goto, có thể dùng trong switch-case. – Lệnh goto làm chương trình khó đọc và khó bảo trì.

Luồng điều khiển không tuần tự [Nonlocal control flow]

– Cho phép thoát khỏi luồng điều khiển thông thường – Ứng dụng:

+ Thoát sớm trong các cấu trúc lặp: Continue & break + Trả về [return] sớm trong các hàm: Return + Bắt các ngoại lệ: Try/catch

Lệnh continue

– Lệnh continue sẽ kết thúc vòng lặp hiện hành và chuyển đến vòng lặp tiếp theo. – Khi gặp lệnh này, các câu lệnh còn lại trong thân của vòng lặp sẽ được bỏ qua. Vd: int count =0; for [int i=0; i

Chủ Đề