一:Go编程语言规范--块、声明、作用域

1.块

块为一对大括号括住的声明和语句。块 = "{" { 语句 ";" } "}" .

除显式源码块外,还有隐式块:

    1. 全域块 包含所有的Go源码文本。
    2. 每个都有包含其所有Go源码文本的 包块
    3. 每个文件都有包含其所有Go源码文本的 文件块
    4. 每个 iffor 和switch 语句都被视为处于其自身的隐式块中。
    5. 每个 switch 或 select 语句中的子句其行为如同隐式块。

块可嵌套并会影响作用域。

2.标识符

标识符被用来命名程序实体,例如变量和类型。一个标识符由一个或多个字母和数字组成。 标识符的第一个字符必须是字母。

给定一个标识符集,若其中一个标识符不同于该集中的任一标识符,那么它就是唯一的。 若两个标识符拼写不同,或它们出现在不同的包中且未 导出,那么它们就是不同的。否则,它们就是相同的。

空白标识符

空白标识符 通过下划线字符 _ 表示, 它可像其它标识符一样用于声明,但该标识符不能传入一个新的绑定。

预声明标识符

在全局块中,以下标识符是隐式声明的:

类型:
	bool byte complex64 complex128 error float32 float64
	int int8 int16 int32 int64 rune string
	uint uint8 uint16 uint32 uint64 uintptr
常量:
	true false iota
零值:
	nil
函数:
	append cap close complex copy delete imag len
	make new panic print println real recover

已导出标识符

标识符可被 导出 以允许从另一个包访问。同时符合以下条件即为已导出标识符:

    1. 标识符名的第一个字符为Unicode大写字母(Unicode类别“Lu”);且
    2. 该标识符在包块中已声明或为字段名或 方法名

其它所有标识符均为未导出的。

关键字

以下为保留关键字,不能用作标识符。

break        default      func         interface    select
case         defer        go           map          struct
chan         else         goto         package      switch
const        fallthrough  if           range        type
continue     for          import       return       var

3.声明和作用域

声明可将非空白标识符"_"绑定到一个常量、类型、变量、函数或包。 在程序中,每个标识符都必须被声明。

作用域 即为已声明标识符所表示的常量、类型、变量、函数或包在源代码中的作用范围。

作用域说明:

  1. 预声明标识符的作用域为全域块。
  2. 在顶级(即在任何函数之外)声明的表示常量、类型、变量或函数(而非方法)的标识符其作用域为该包块。
  3. 已导入包的包名作用域为包含该导入声明的文件块。
  4. 表示方法接收器、函数形参或返回值变量的标识符,其作用域为该函数体。
  5. 在函数中声明为常量或变量的标识符,其作用域始于该函数中具体常量实现或变量实现ShortVarDecl表示短变量声明)的结尾,止于最内部包含块的结尾。
  6. 在函数中声明为类型的标识符,其作用域始于该函数中具体类型实现的标识符,止于最内部包含块的结尾。

注意:

  • 同一标识符不能在同一中声明两次,且在文件与包块中不能同时声明。
  • 在块中声明的标识符可在其内部块中重新声明。 当其内部声明的标识符在作用域中时,即表示其实体在该内部声明中声明。
  • 包子句(package xxx)并非声明;包名不会出现在任何作用域中。 其目的是为了识别该文件是否属于相同的包并为导入声明指定默认包名。

标签作用域:

标签通过标签语句声明(标识符:语句),并用于 break、continue 和 goto 语句.例如:

L:
    for i < n {
        switch i {
        case 5:
            break L
        }
    }

定义不会使用的标签是非法的。与其它标识符相反,标签并不限定作用域且与非标签标识符并不冲突。 标签的作用域为除任何嵌套函数体外其声明的函数体。

4.各种声明

常量声明

const Pi float64 = 3.14159265358979323846
const zero = 0.0       // 无类型化浮点常量
const (
    size int64 = 1024
    eof        = -1    // 无类型化整数常量
)
const a, b, c = 3, 4, "foo"  // a = 3, b = 4, c = "foo", 无类型化整数和字符串常量
const u, v float32 = 0, 3    // u = 0.0, v = 3.0

iota

iota可以被认为是一个可被编译器修改的常量,在每一个const关键字出现时被重置为0,然后在下一个const出现之前,每出现一次iota,其所代表的数字会自动增1

const (  // iota重置为0
    c0 = iota  // c0 == 0
    c1 = iota  // c1 == 1
    c2 = iota  // c2 == 2
)

const (
    Sunday = iota
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Partyday
    numberOfDays  // 该常量未导出
)

在表达式列表中,每个 iota 的值都相同,因为它只在每个常量实现后增量。

const (
    bit0, mask0 = 1 << iota, 1<<iota - 1  // bit0 == 1, mask0 == 0
    bit1, mask1                           // bit1 == 2, mask1 == 1
    _, _                                  // skips iota == 2
    bit3, mask3                           // bit3 == 8, mask3 == 7
)

类型声明

声明类型不继承任何方法绑定到现存类型, 但接口类型或复合类型元素的方法集保持不变:

// Mutex为带有Lock和Unlock两个方法的数据类型.
type Mutex struct         { /* Mutex字段 */ }
func (m *Mutex) Lock()    { /* Lock实现*/ }
func (m *Mutex) Unlock()  { /* Unlock实现*/ }

// NewMutex和Mutex拥有相同的组成,但它的方法集为空.
type NewMutex Mutex

// PtrMutex的基础类型的方法集保持不变.
// 但PtrMutex的方法集为空.
type PtrMutex *Mutex

// *PrintableMutex的方法集包含方法
// Lock和Unlock绑定至其匿名字段Mutex.
type PrintableMutex struct {
    Mutex
}

// MyBlock为与Block拥有相同方法集的接口类型.
type MyBlock Block

类型声明可用来定义不同的布尔值、数字或字符串类型并对其附上方法:

type TimeZone int

const (
    EST TimeZone = -(5 + iota)
    CST
    MST
    PST
)

func (tz TimeZone) String() string {
    return fmt.Sprintf("GMT+%dh", tz)
}

变量声明

变量声明将一个标识符绑定至一个创建的变量并赋予其类型和可选的初始值。
若给定一个表达式列表,则变量通过按顺序将该表达式赋予该变量(§赋值)来初始化;所有表达式必须用尽且所有变量根据它们初始化。
否则,每个变量初始化为其 零值。若该类型已存在,每个变量都赋予该类型。
否则,该类型根据该表达式列表赋值。
若该类型不存在且其对应表达式计算结果为无类型化常量, 则该声明变量的类型由其赋值描述。

实现限制:若在函数体内声明不会使用的变量,编译器可能将其判定为非法

var i int
var U, V, W float64
var k = 0
var x, y float32 = -1, -2
var (
    i       int
    u, v, s = 2.0, 3.0, "bar"
)
var re, im = complexSqrt(-1)
var _, found = entries[name]  // 映射检查;只与“found”有关

短变量声明

短变量声明只能出现在函数内部。在某些情况下,例如初始化 if、 for、或 switch 语句时,它们可用来声明局部临时变量

i, j := 0, 10
f := func() int { return 7 }
ch := make(chan int)
r, w := os.Pipe(fd)  // os.Pipe() 返回两个值
_, y, _ := coord(p)  // coord() 返回三个值;只与和y同位的值相关

不同于常规变量声明,在至少有一个非空白变量时,短变量声明可在相同块中,对原先声明的变量以相同的类型重声明。 因此,重声明只能出现在多变量短声明中。 重声明不能生成新的变量;它只能赋予新的值给原来的变量。

field1, offset := nextField(str, 0)
field2, offset := nextField(str, offset)  // 重声明 offset  在同一个块中使用var 重复声明是非法的
a, a := 1, 2                              // 非法:重复声明了 a,或者若 a 在别处声明,但此处没有新的变量

函数声明

函数声明可省略函数体。这样的标识符为Go外部实现的函数提供签名,例如汇编例程。

func min(x int, y int) int {
    if x < y {
        return x
    }
    return y
}

func flushICache(begin, end uintptr)  // 外部实现

方法声明

方法为带 接收者 的函数。方法声明将标识符,即 方法名 绑定至方法。 它也将该接收者的 基础类型 关联至该方法。
接收者类型必须为形式 T 或 *T,其中 T 为类型名。 
由 T 表示的类型称为接收者的 基础类型; 它不能为指针或接口类型且必须在同一包中声明为方法。

若该接收器的值并未在该方法体中引用,其标识符可在声明中省略。这同样适用于一般函数或方法的形参。

func (p *Point) Length() float64 {
    return math.Sqrt(p.x * p.x + p.y * p.y)
}

func (p *Point) Scale(factor float64) {
    p.x *= factor
    p.y *= factor
}

func (Point) Scale(factor float64) {
    ....
}
 
时间: 2024-10-14 08:57:18

一:Go编程语言规范--块、声明、作用域的相关文章

ES6块级作用域及新变量声明(let)

很多语言中都有块级作用域,但JS没有,它使用var声明变量,以function来划分作用域,大括号"{}" 却限定不了var的作用域.用var声明的变量具有变量提升(declaration hoisting)的效果. ES6里增加了一个let,可以在{}, if, for里声明.用法同var,但作用域限定在块级,let声明的变量不存在变量提升. 示例1: 块级作用域 if function getVal(boo) {     if (boo) {         var val = '

关于Javascript没有块级作用域和变量声明提升

Javascript是没有块级作用域的,在语句块中声明的变量将成为语句块所在代码片段的局部变量.例如: 1 if(true){ 2 var x=3; 3 } 4 console.log(x); 结果输出3. 再如: 1 var x=5; 2 3 function a(){ 4 if(!x){ 5 var x=10; 6 } 7 console.log(x); 8 } 9 a(); 结果是10.因为变量声明的提升,原理是这样的,举个例子: 1 if(a==undefined){ 2 alert("

JS-闭包(Closures)和let声明块级作用域变量

闭包: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures 闭包是函数和声明该函数的词法环境的组合. let: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/let let 语句声明一个块级作用域的本地变量,并且可选的将其初始化为一个值. 例:闭包和let修正匿名函数访问的变量 function foo(){ v

《你不知道的JavaScript》 函数作用域和块级作用域

一.函数作用域 可用在代码外添加包装函数,将内部的变量和函数定义隐藏. var a = 2; function foo() { // <- - 添加这一行 var a = 3; console.log( a ); //3 } // <- - 以及这一行 foo(); // <- - 以及这一行 console.log( a ); //2 这种技术必须声明一个具名函数foo(),foo本身“污染”了所在作用域.其次,必须显式地通过函数名( foo( ) )调用这个函数才能运行其中的代码.

ecma6块级作用域

转载自:http://blog.sina.com.cn/s/blog_77f241790102vqyf.html 在很多语言中都有块级作用域,但JS没有,它使用var 声明变量,以function来划分作用域,大括号{}却限定不了var的作用域.用var声明的变量具有变量提升(declaration hoisting)的效果 ES6里增加了let,可以在{},if ,for里声明.用法同var ,但作用域限定在块级,let声明的变量不存在变量提升. 一.let命令 示例1:{}块 { let a

0140 JavaScript作用域:概述、全局作用域、函数作用域、块级作用域

1.1 作用域概述 通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域.作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突. JavaScript(es6前)中的作用域有两种: 全局作用域 局部作用域(函数作用域) 1.2 全局作用域 作用于所有代码执行的环境(整个 script 标签内部),或者一个独立的 js 文件. 1.3 局部作用域 作用于函数内的代码环境,就是局部作用域. 因为跟函数有关系,所以也称为函数作

bala001 浏览器中的JavaScript执行机制:09 | 块级作用域:var缺陷以及为什么要引入let和const?

前言:该篇说明:|请见 说明 —— 浏览器工作原理与实践 目录 在前面<07 | 变量提升:JavaScript 代码是按照顺序执行的吗?>这篇文章中,我们已经讲解了 JavaScript 中变量提升的相关内容,正是由于 JavaScript 存在变量提升这种特性,从而导致了很多于直觉不符的代码,这也是 JavaScript 的一个重要设计缺陷. 虽然 ECMAScript6(以下简称 ES6 )已经通过引入块级作用域并配合 let.const 关键字,来避开了这种设计缺陷,但是由于 Java

ES6之块级作用域

一.前言 在ECMAScript6(以下简称ES6)之前,ECMAScript的作用域只有两种: 1.  全局作用域: 2.  函数作用域. 正是因为有这两种作用域,所以在JavaScript中出现一术语--“变量提升(hoisting)”. 如下: function func(){ console.log(test); var test = 1; }; func(); 在node环境执行上述代码,结果为: 之所以为’undefined’,原因就在于‘变量提升’,在进入func函数时,将所有通过

模仿块级作用域

在JavaScript中没有块级作用域的概念.这就意味着在块语句中定义的变量,实际上是在包含函数中而非语句中创建的. <script> for(var i=0;i<5;i++) { } alert(i); </script> 就上面这个例子中,可以弹出i是5,因为for语句事实上是包含在window.onload= function(){}这个函数中,alert也在这个函数中. 而在java.c++中i只会在for循环的语句块中定义,循环一但结束,变量i就会被销毁.而在Jav