【块 (编程)】
在计算机编程中，块（block）或代码块是将源代码组织在一起的词法结构。块构成自一个或多个声明和语句。编程语言允许创建块，包括嵌入其他块之内的块，就叫做块结构编程语言。块和子程序是结构化编程的基础，结构化所强调的控制结构是用块来形成的。
在编程中块的功能是确使成组的语句被当作如同就是一个语句，限定在一个块中声明的对象如变量、过程和函数的词法作用域，使得它们不冲突于在其他地方用到的同名者。在块结构编程语言中，在块外部的对象名字在块内部是可见的，除非它们被声明了相同名字的对象所遮掩。
==历史==
块结构的想法是在1950年代开发最初的Autocode期间发展出来的，并形式化于ALGOL 58和ALGOL 60报告中。Algol 58介入了“复合”（compound）语句的概念，它只与控制流程有关。在“ALGOL 60报告”中，介入了块和块作用域的概念，随后在“修订报告”中作出更明确定义：“一序列的声明，跟随着一序列的语句，并被包围在begin和end之间，构成一个块。所有声明以这种方式出现在一个块中，并只在这个块中有效。”
==语法==
块在不同语言中使用不同的语法。两个广大的家族是：
* ALGOL语言家族，ALGOL 60及其后继者，使用关键字begin和end或等价者来界定块。ALGOL 68成为了Expression-oriented programming language，偏好使用圆括号(和)。C语言家族承袭了BCPL，使用花括号{和}来界定块。Pascal语言家族，使用begin和end来界定复合语句。
* Lisp语言家族，使用具有语法关键字如prog或let的S-表达式来表示块，S-表达式是圆括号包围的前缀表示法。
此外还有：
* 越位规则，源于ISWIM使用缩进表示块结构，采用越位规则的语言有occam、ABC、Python和Genie等。
* 在ALGOL 68中，条件和迭代代码块，可选的使用块保留字反写来终止，比如：if ~ then ~ elif ~ then ~ else ~ fi，case ~ in ~ out ~ esac和for ~ while ~ do ~ od。继承此风格的有：1974年Edsger W. Dijkstra的守卫命令语言和Bourne shell等。
* 一些结构化编程语言，如FORTRAN 77、Modula-2、Ada和Visual Basic等，对控制结构加结束关键字，比如：IF ~ THEN ~ ELSIF ~ THEN ~ ELSE ~ END。
==限制==
受ALGOL影响的一些语言，支持带有声明的块，但不完全支持所有声明，例如C及其很多派生语言，不允许在块内的函数定义（nested function）。Pascal家族语言，在程序、过程和函数块的begin和end内部，不支持使用带有自己声明的块，只支持复合语句，用来确使语句序列在if、while、repeat和其他控制语句内被组合在一起。
==基本语义==
块的语义是双重的。首先，它向编程者提供了建立任意大和复杂的结构，并把它当作一个单元的一种途径。其次，它确使编程者能限制变量的作用域，有时可以限制已经被声明了的其他对象的作用域。
在早期语言比如FORTRAN和BASIC中，没有语句块或控制结构。直到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代码相比，处理附加税代码不再嵌入到处理正税代码之中，去除了附加税阈值要大于正税阈值，才能处理附加税的隐含条件。使用块结构，能明晰编程者的意图，使代码的结构更加密切反映出编程者的思考；再凭借缩进增进可读性，可使代码更加容易理解和修改。
在早期语言中，变量有着宽广的作用域。例如，一个叫做IEMPNO的整数变量，可以用在一个Fortran子例程的某部份中，指示一个雇员的社会安全号码（ssn），但是在同一个子例程的维护工作中，一个编程者可能偶然的使用了相同的变量IEMPNO，并用于了不同的用途，这可能导致一个难于跟踪的缺陷。
块结构使得编程者易于将作用域控制到细微级别。例如下述Scheme代码，列出作为管理者的雇员名字和他的下属数目，以及每个下属的名字和角色：
; 语言：R5RS标准Scheme
(let ((empno (ssn-of employee-name)))
(when (is-manager empno)
(let ((employees (length (underlings-of empno))))
(printf "~a has ~a employees working under him:~%"
employee-name employees)
(for-each
(lambda (empno)
;; 在这个lambda表达式之内变量empno指称一个下属的ssn。
;; 在外部的表达式中变量empno指称的管理者的ssn，被遮蔽了。
(printf "Name: ~a, role: ~a~%"
(name-of empno) (role-of empno)))
(underlings-of empno)))))
在这个片段中，管理者及其下属二者各自的ssn，都用empno来标识，但是因为下属ssn被声明于内部的块之中，它与持有管理者ssn的同名变量不相互影响。在实践中，出于清晰性的考虑，编程者更可能选择明显不同的变量名字，但是即使选择重名，也难以不经意的介入一个缺陷。
==提升==
在一些情境下，在一个块中的代码的求值，如同这个代码实际上是写在块的顶部或块的外部一样。这经常通俗的叫做“提升”（hoisting），这包括了：
* 循环不变代码外提，是将在循环内不变的代码在循环之前求值的编译器优化。
* 变量提升，是JavaScript的辖域规则，在这里变量有函数辖域，并且表现得如同它们被声明（而非定义）在函数的顶部一样。