Các cấu trúc điều khiển khác

7 478 0
Các cấu trúc điều khiển khác

Đang tải... (xem toàn văn)

Thông tin tài liệu

Các cấu trúc điều khiển khác Toán tử last Trong một số bài tập trớc đây bạn có thể đã nghĩ, Nếu tôi có đợc một câu lệnh break của C ở đây, thì đã xong rồi. Cho dù bạn không nghĩ nh thế, thì hãy cứ để tôi nói cho bạn về sự tơng đơng của Perl để thoát sớm khỏi chu trình : toán tử last. Toán tử last ngắt khối chu trình bao quanh ở bên trong nhất, gây ra việc thực hiện tiếp tục với câu lệnh đi ngay sau khối đó. Chẳng hạn: while (cái gì đó) { cái gì đó ; cái gì đó ; cái gì đó ; if (điều kiện nào đó) { cái gì đó khác ; cái gì đó khác ; last ; # nhẩy ra khỏi chu trình while } thêm nữa ; thêm nữa ; } # last nhẩy tới đây Nếu điều kiện nào đó là đúng, thì cái gì đó khác sẽ đợc thực hiện, và thế rồi toán tử last buộc chu trình while phải kết thúc. Toán tử last chỉ tính tới khối chu trình, không tính khối cần để tạo nên kết cấu cú pháp nào đó. Điều này có nghĩa là khối tạo nên nhánh then của câu lệnh if không đợc tính tới - chỉ khối tạo nên for, foreach, while và các khối trần mới đợc tính. (Khối trần là khối không thuộc phần khác của một kết cấu lớn hơn, nh một chu trình, hay một trình con, hay một câu lệnh if/then/else). Giả sử tôi muốn xem liệu thông báo th đã đợc cất giữ trong một tệp có là từ tôi hay không. Một thông báo nh vậy có thể giống nh là: From: merlyn@ora.com (Randal L. Schwartz) To: stevet@ora.com Date: 01-SEP-93 08:16:24 PM PDT - 0700 Subject: A sample mail message Heres the body of the mail message. And here is some more. Tôi phải duyệt qua thông báo này từ dòng bắt đầu với From: và rồi để ý liệu dòng này có chứa tên đăng nhập của tôi hay không, merlyn. Tôi có thể làm điều đó nh thế này: while (<STDIN>) { # đọc dòng vào if (/^From:/) { # nó có bắt đầu với From: không? Nếu có . if (/merlyn/) { # nó là từ tôi! print Email from Randal! Its about time!\n; } last ; # không cần tìm From: nữa, cho nên ra } # kết thúc if from: if (/^$/) { # dòng trống ? last ; # nếu đúng thế thì đừng kiểm tra thêm nữa } } # kết thúc while Lu ý rằng một khi dòng có chứa From: đợc tìm thấy thì chúng ta đi ra khỏi chu trình chính bởi vì tôi muốn xem chỉ dòng From: đầu tiên. Cũng lu ý rằng một đầu đề th kết thúc tại dòng trống đầu tiên, cho nên chúng ta có thể ra khỏi chu trình chính nữa. Toán tử next Giống nh last, next cũng làm thay đổi luồng thực hiện theo trình tự thông thờng. Tuy nhiên, toán tử next làm cho việc thực hiện bỏ qua phần còn lại của khối chu trình đợc bao bên trong nhất mà không kết thúc khối này * . Nó đợc dùng nh thế này: while (cái gì đó) { phần thứ nhất ; phần thứ nhất ; phần thứ nhất ; if (điều kiện nào đó) { phần nào đó ; phần nào đó ; next ; # nhẩy ra khỏi chu trình while } phần khác ; phần khác ; # next tới đây } Nếu điều kiện nào đó là đúng, thì phần nào đó đợc thực hiện, và phần khác bị bỏ qua. * * Nếu có một khối continue cho chu trình này, mà chúng ta thì cha thảo luận tới, thì toán tử next đi tới chỗ bắt đầu của khối continue thay vì tới cuối khối này. Khá gần. Lần nữa, khối của một câu lệnh if không đợc tính tới nh khối chu trình. Toán tử redo Cách thứ ba mà bạn có thể nhẩy qua trong một khối chu trình là bằng redo. Toán tử này nhẩy tới chỗ bắt đầu của khối hiện tại (không tính lại biểu thức điều kiện), kiểu nh: while (cái gì đó) { # redo tới đây cái gì đó ; cái gì đó ; cái gì đó ; if (điều kiện nào đó) { phần nào đó ; phần nào đó ; redo ; } phần khác ; phần khác ; phần khác ; } Một lần nữa, khối if không đợc tính tới. Chỉ tính các khối chu trình. L ý rằng với redo và last và khối trần, bạn có thể tạo nên chu trình vô hạn mà đi ra từ giữa, kiểu nh: { phần bắt đầu ; phần bắt đầu ; phần bắt đầu ; if (điều kiện nào đó) { last ; } phần sau ; phần sau ; phần sau ; redo ; } Điều này sẽ phù hợp cho một chu trình kiểu while mà cần tới việc có một phần nào đó của chu trình này đợc thực hiện nh việc khởi đầu trớc phép kiểm thử thứ nhất. (Trong mục Bộ thay đổi biểu thức, dới đây, tôi sẽ chỉ ra cho bạn cách viết câu lệnh if với ít kí tự ngắt hơn.) Khối có nhãn Điều gì xảy ra nếu bạn muốn nhẩy ra khổi một khối có chứa khối bên trong nhất, hay nói theo cách khác, ra khỏi hai khối lồng nhau ngay một lúc? Trong C, bạn phải viện tới toán tử goto để đi ra. Không cần phải làm nhu vậy trong Perl - bạn có thể dùng last, next và redo tại bất kì khối kết nào bằng việc cho khối một cái tên có nhãn. Nhãn là một kiểu tên khác từ một không gian tên khác mà tuân theo cùng qui tắc nh vô hớng, mảng, mảng kết hợp và trình con. Tuy nhiên, nh chúng ta thấy, một nhãn không có kí tự ngắt đi đầu đặc biệt (nh $ cho vô hớng, & cho trình con, vân vân), cho nên một nhãn có tên print sẽ xung đột với từ dành riêng print và sẽ không đợc phép. Bởi lí do này, Larry gợi ý bạn hãy chọn các nhãn bao gồm toàn chữ hoa và số, mà anh ấy đảm bảo sẽ không bao giờ bị chọn nhầm thành một từ dành riêng trong tơng lai. Bên cạnh đó, tất cả các chứ hoa cho phép dễ nhìn thấy hơn trong một văn bản chơng trình mà phần lớn là chữ thờng. Một khi bạn đã chọn cẩn thận nhãn, thì nó sẽ đứng ngay trớc câu lệnh có chứa khối, theo sau dấu hai chấm, kiểu nh thế này: SOMELABEL: while (điều kiện) { câu lệnh ; câu lệnh ; câu lệnh ; if (điều kiện khác) { last SOMELABEL ; } } L ý rằng tôi đã thêm SOMELABEL, nh một tham biến vào câu lệnh last. Tham biến này bảo cho Perl ra khỏi khối có tên SOMELABEL, thay vì ra khỏi khối bên trong nhất. Trong trờng hợp này, chúng ta không có cái gì khác ngoài khối bên trong nhất. Nhng giả sử tôi có các chu trình lồng nhau: OUTER: for ($i = 1; $i <= 10 ; $i++) { INNER: for ($j = 1 ; $j >= 10 ; $j++) { if ($i + $j == 63) { print $i lần $j là 63!\n ; last OUTER; } if ($j >= $i) { next OUTER ; } } } Tập hợp các câu lệnh này thử tất cả các giá trị kế tiếp của hai số nhỏ nhất đợc nhân với nhau cho tới khi nó tìm ra một cặp có tích là 63 (7 và 9). Lu ý rằng một khi đã tìm đợc một cặp thì không cần phải kiểm tra các số khác nữa, cho nên câu lệnh if thứ nhất ra khỏi cả hai chu trình for bằng việc dùng last với nhãn. Câu lệnh if thứ hai cố gắng đảm bảo rằng số lớn hơn trong hai số bao giờ cũng là số thứ nhất bằng việc bỏ qua việc lặp tiếp của chu trình bên ngoài ngay khi điều kiện này không còn xảy ra nữa. Điều này có nghĩa là các số sẽ đợc kiểm thử với ($i, $j) là (1,1), (2,1), (2,2), (3,1), (3,2), (3,3), (4,1) vân vân. Cho dù khối bên trong nhất đợc gắn nhãn, thì các toán tử last, next, và redo không có tham biến tuỳ chọn (nhãn) vẫn vận hành tôn trọng khối bên trong nhất. Cũng vậy, bạn không thể dùng nhãn để nhẩy vào trong một khối - chỉ để nhẩy ra khối. Các toán tử last, next hay redo phải ở bên trong khối. Bộ thay đổi biểu thức Xem nh một cách khác để chỉ ra nếu thế này, thì thế kia, Perl cho phép bạn gắn nhãn cho một bộ sửa đổi if lên một biểu thức vốn là một biểu thức đứng riêng. Kiểu nh: biểu thức nào đó if biểu thức điều khiển ; Trong trờng hợp này, biểu thức điều khiển đợc tính trớc để xét giá trị chân lí của nó (bằng việc dùng cùng qui tắc nh thờng lệ), và nếu đúng, thì biểu thức nào đó sẽ đợc tính tiếp. Điều này đại thể tơng đơng với: if (biểu thức điều khiển nào đó) { biểu thức nào đó ; } ngoại trừ rằng bạn không cần thêm dấu ngắt phụ, câu lệnh này đọc ngợc lại, và biểu thức phải là một biểu thức đơn (không phải là một khối câu lệnh). Tuy nhiên, nhiều lần cách mô tả ngợc này lahi biến thành cách tự nhiên nhất để phát biểu vấn đề, trong khi cũng tiết kiệm đợc vài nhát gõ. Chẳng hạn, sau đây là cách bạn có thể ra khỏi chu trình khi một điều kiện nào đó nảy sinh: LINE: while (<STDIN>) { last LINE if /^From: / ; } Bạn xem dễ viết làm sao. Và bạn thậm chí còn có thể đọc nó theo kiểu tiếng Anh: dòng cuối nếu nó bắt đầu với From. Các dạng song song khác bao gồm những dạng sau: exp2 unless exp1; # giống: unless (exp1) { exp2 ; } exp2 while exp1; # giống: while (exp1) { exp2 ; } exp2 until exp1; # giống: util (exp1) { exp2 ; } L ý rằng tất cả các dạng này đều tính exp1 trớc rồi dựa trên đó, tính hay không tính cái gì đó với exp2. Chẳng hạn, sau đây là cách tìm ra luỹ thừa đầu tiên của hai số lớn hơn một số đã cho: chop ($n = <STDIN>) ; $i = 1; # khởi đầu $i *= 2 until $i > $n ; # lặp cho tới khi ta tìm ra nó. Các dạng này không lồng nhau - bạn không thể nói đợc exp3 while exp2 if exp1. Điều này là vì dạng exp2 if exp1 không còn là một biểu thức, mà là một câu lệnh hoàn toàn, và bạn không thể gắn thêm một trong các bộ sửa đổi này vào sau câu lệnh. &&, || và ?: xem nh các cấu trúc điều khiển Những cấu trúc này trông tựa nh các kí tự ngắt, hay một phần của biểu thức. Liệu chúng có thể thực sự đợc coi là các cấu trúc điều khiển không? Thế này, theo cách nghĩ Perl, gần nh bất kì cái gì cũng đều có thể cả, cho nên bạn hãy xem điều tôi nói ở đây. Thông thờng, bạn bắt gặp nếu cái này, thì cái nọ. Trớc đây chúng ta đã thấy hai dạng này: if (cái này) { cái nọ ; } # một cách cái nọ if cái này ; # cách khác Đây là cách thứ ba (và hãy tin tôi đi, vẫn còn nữa đấy): cái này && cái nọ ; Tại sao nó lại làm việc? Nó chẳng phải là toán tử logic và sao? Bạn hãy kiểm tra xem cái gì xảy ra khi cái này lấy giá trị đúng hay sai: Nếu cái này là đúng, thế thì giá trị của toàn bộ biểu thức vẫn còn cha đợc biết tới, vì nó phụ thuộc vào giá trị của cái nọ. Cho nên cái nọ phải đợc tính. Nếu cái này là sai, thế thì chẳng cần gì mà nhìn vào cái nọ nữa, bởi vì giá trị của toàn bộ biểu thức phải là sai rồi. Vì chẳng cần gì phải tính cái nọ nên chúng ta có thể bỏ qua. Và trong thực tế, đây là điều mà Perl làm. Perl tính cái nọ chỉ khi cái này là đúng, làm cho nó thành tơng đơng với hai dạng trớc. Giống thế, toán tử logic hoặc giống nh câu lệnh unless (hay bộ sửa đổi unless). Cho nên bạn có thể thay thế: unless (cái này) { cái nọ ; } bằng cái này || cái nọ ; Nếu bạn quen thuộc với việc dùng các toán tử này trong lớp vỏ để kiểm soát các chỉ lệnh thực hiện điều kiện, thì bạn sẽ thấy rằng chúng vận hành tơng tự trong Perl. Cuối cùng toán tử ba ngôi kiểu C: exp1 ? exp2 : exp3 ; tính exp2 nếu exp1 đúng, ngợc lại tính exp3. Cũng dờng nh là chúng ta nói: if (exp1) { exp2 ; } else { exp3 ; } nhng một lần nữa không có tất cả các dấu ngắt đó. Chẳng hạn, bạn có thể viết: ($a < 10) ? $b = $a : $a = $b ; Ta nên dùng cái nào đây? Tuỳ vào tâm trạng bạn thôi, đôi khi, hay tuỳ theo từng phần biểu thức lớn đến đâu, hay liệu ta cần thêm đóng mở ngoặc nào bởi vì sự xung khắc thứ tự u tiên. Bạn hãy nhìn vào chơng trình của ngời khác và xem chúng làm gì. Có lẽ bạn sẽ thấy đôi điều ở đó. Larry gợi ý rằng bạn hãy đặt phần quan trọng nhất của biểu thức lên trớc, để cho nó nổi bật ra. Bài tập 1. Hãy mở rộng bài toán của chơng trớc để lặp lại phép toán đó cho tới khi từ end đợc đa vào cho một trong các giá trị. (Hớng dẫn: bạn hãy dùng một chu trình vô hạn, và rồi thực hiện last nếu giá trị đa vào là end.) . thêm một trong các bộ sửa đổi này vào sau câu lệnh. &&, || và ?: xem nh các cấu trúc điều khiển Những cấu trúc này trông tựa nh các kí tự ngắt,. sự đợc coi là các cấu trúc điều khiển không? Thế này, theo cách nghĩ Perl, gần nh bất kì cái gì cũng đều có thể cả, cho nên bạn hãy xem điều tôi nói ở

Ngày đăng: 28/09/2013, 10:20

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan