電腦編程中,(block)或譯為程式區塊代碼塊,是將原始碼組織在一起的詞法結構。塊構成自一個或多個聲明英語Declaration (computer programming)語句。程式語言允許建立塊,包括嵌入其他塊之內的塊,就叫做塊結構程式語言。塊和子程式結構化編程的基礎,結構化所強調的控制結構可以用塊來形成的。

在編程中塊的功能,是確使成組的語句被當作如同就是一個語句,限定在一個塊中聲明的對象如變數、過程和函式的詞法作用域,使得它們不衝突於在其他地方用到的同名者。在塊結構程式語言中,在塊外部的對象名字在塊內部是可見的,除非它們被聲明了相同名字的對象所遮掩

歷史

塊結構的想法是在1950年代開發最初的Autocode英語Autocode期間發展出來的,並形式化於ALGOL 60報告中。ALGOL 58介入了「複合」(compound)語句的概念,它只與控制流程有關[1]。在「ALGOL 60報告」中,介入了塊和作用域的概念[2]。最終在「修訂報告」中,複合語句被定義為:包圍在語句括號beginend之間的成序列的語句,形成一個複合語句。塊被定義為:成序列的聲明,跟隨著成序列的語句,並被包圍在beginend之間,形成一個塊;所有聲明以這種方式出現在一個塊中,並只在這個塊中有效[3]。塊與複合語句的主要差異是不能從塊外跳轉到塊內的標籤[4]

語法

塊在不同語言家族中使用不同的語法:

此外,複合語句界定還可以採用:

建立控制結構,除了將所控制的語句序列,包圍入複合語句或匿名塊之外,還可以採用其他語法機制:

限制

受ALGOL影響的一些語言支援塊,但有著各自的限制:

  • C家族語言,在塊和複合語句之中不僅支援巢狀入複合語句,還支援嵌入帶有聲明的匿名塊,但不允許聲明巢狀函式英語nested function[8]
  • Pascal家族語言,在語句部份的複合語句之中,不允許存在帶有聲明的匿名塊[6],只支援複合語句,用來在ifwhilerepeat等控制語句內組合語句序列。

基本語意

塊的語意是雙重的。首先,它向編程者提供了建立任意大和複雜的結構,並把它當作一個單元的一種途徑。其次,它確使編程者能限制變數的作用域,有時可以限制已經被聲明了的其他對象的作用域。

在早期語言比如FORTRANBASIC中,沒有語句塊或控制結構。直到1978年標準化FORTRAN 77之前,都沒有「塊狀IF」語句,要實現按條件選擇,必須訴諸GOTO語句。例如下述FORTRAN代碼片段,從雇員工資中分別扣除超出正稅閾值部分的稅款,和超出附加稅閾值部分的附加稅款:

C     语言:ANSI标准FORTRAN 66
C     初始化要计算的值
      PAYSTX = .FALSE.
      PAYSST = .FALSE.
      TAX = 0.0
      SUPTAX = 0.0
C     如果雇员挣钱小于等于正税阈值则跃过税款扣除
      IF (WAGES .LE. TAXTHR) GOTO 100
      PAYSTX = .TRUE.
      TAX = (WAGES - TAXTHR) * BASCRT
C     如果雇员挣钱小于等于附加税阈值则跃过附加税扣除
      IF (WAGES .LE. SUPTHR) GOTO 100
      PAYSST = .TRUE.
      SUPTAX = (WAGES - SUPTHR) * SUPRAT
  100 TAXED = WAGES - TAX - SUPTAX

由於程式的邏輯結構不反映在語言中,分析出給定語句在何時執行可能會有困難。

塊允許編程者把一組語句當作一個單元。例如,在與上述FORTRAN代碼相對應的Pascal代碼片段:

{ 语言:Jensen与Wirth版标准Pascal }
if wages > tax_threshold then
begin
    paystax := true;
    tax := (wages - tax_threshold) * tax_rate
    { 附加税处理代码不再嵌套在这里 }
end
else begin
    paystax := false;
    tax := 0
end;
if wages > supertax_threshold then
begin
    pays_supertax := true;
    supertax := (wages - supertax_threshold) * supertax_rate
end
else begin
    pays_supertax := false;
    supertax := 0
end;
taxed := wages - tax - supertax;

與上述FORTRAN代碼相比,上例中出現在初始化中的那些預設值,通過複合語句即不帶聲明的塊結構,被分別放置作出有關判斷的地方。此外,處理附加稅代碼不再嵌入到處理正稅代碼之中,去除了附加稅閾值要大於正稅閾值,才能處理附加稅的隱含條件。使用塊結構,能明晰編程者的意圖,使代碼的結構更加密切反映出編程者的思考;再憑藉某種風格的縮排增進可讀性,可使代碼更加容易理解和修改。

在早期語言中,在次常式中變數的作用域遍及整個次常式。假想在一個Fortran次常式中,完成了與管理者有關的任務,這裡可能用到叫做IEMPNO的一個整數變數,指示作為管理者的雇員的社會安全號碼(SSN);後來在這個次常式的維護工作中,又增加與下屬們有關的任務,此時編程者可能不經意間使用同名變數IEMPNO,指示了作為這個管理者的下屬的雇員的SSN,這就會導致一個難於跟蹤的缺陷。

塊結構使得編程者能夠容易地將作用域控制到細微級別。例如完成有關雇員任務的Scheme代碼片段:

;; 语言:R5RS标准Scheme
(let ((empno (ssn-of employee-name)))
  (when (is-manager? empno) ;; when已列入R7RS-small标准
    (let ((employee-list (underlings-of empno)))
      (display
        ;; format是SRFI-28和SRFI-48规定的字符串格式化过程
        (format "~a has ~a employees working under him:~%"
          employee-name (length employee-list)))
      (for-each
        (lambda (empno)
          (display
            (format "Name: ~a, role: ~a~%"
              (name-of empno) (role-of empno))))
        employee-list))))

這裡在外層通過繫結let將管理者的SSN繫結到了局部變數empno,在其形成的塊的作用域中列出管理者的雇員名字和他的下屬數目;隨後通過for-each高階函式,將他所有下屬的SSN逐個繫結到匿名函式lambda的形式參數empno上,執行此匿名函式列出這個下屬的名字和角色;這個形式參數的作用域是此匿名函式的主體,它與其外層的局部變數,識別碼重名但不相互影響。在實踐中,出於清晰性的考慮,編程者更可能選取明顯不同的變數名字,但是即使名字選取存在重複,也難以在不經意間介入一個缺陷。在基於S-表達式的語言中,經常見到大量的巢狀圓括號,故而其代碼必須採用良好的縮排

提升

在一些語言中,變數可以聲明為有函式作用域即使它位於函式的內嵌塊之中。例如在JavaScript中,變數應當總是在使用之前被聲明,它曾經允許賦值到未聲明變數,會為此建立為未聲明的全域變數,這在strict模態下是個錯誤。以var聲明的變數有函式作用域,而非以letconst聲明的變數可從屬的塊作用域。以var聲明的變數會被提升(hoist),這意味著可以在這個函式的作用域內任何地方提及這個變數,即使還未觸及到它的聲明,從而可以將var聲明視為被提舉(lift)到它所在函式的頂部或全域作用域。但是如果在其聲明之前訪問了一個變數,這個變數的值總是未指定的。

參見

參照

Wikiwand in your browser!

Seamless Wikipedia browsing. On steroids.

Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.

Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.