Go编程语言规范


原文链接: Go编程语言规范

Go编程语言规范
Go编程语言规范

介绍

Go是一种设计用于系统编程的通用语言。它是强类型和垃圾回收,并且显式支持并发编程。程序是从包中构建的 ,其属性允许有效地管理依赖关系。现有的实现使用传统的编译/链接模型来生成可执行的二进制文件。go的语法是紧凑和规则的,允许通过自动工具(如集成开发环境)轻松分析。

源代码
源代码是以UTF-8编码的Unicode文本 。文本不是规范化的,所以单个重音代码点与组合口音和字母构造的同一个字符不同; 那些被视为两个代码点。为了简单起见,本文档将使用不合格的术语字符来引用源文本中的Unicode代码点。每个代码点是不同的; 例如,大小写字母是不同的字符。

实现限制:为了与其他工具兼容,编译器可能不允许源文本中的NUL字符(U + 0000)。
实现限制:为了与其他工具兼容,编译器可能会忽略UTF-8编码的字节顺序标记(U + FEFF),如果它是源文本中的第一个Unicode代码点。源中的任何其他位置可能禁止字节顺序标记。

字母和数字

下划线字符_(U + 005F)被认为是一个字母。

letter = unicode_letter | “_”。
decimal_digit =“0”...“9”。
octal_digit =“0”...“7”。
hex_digit =“0”...“9”| “A”...“F”| “a”...“f”。

注释

评论作为程序文件。有两种形式:

行注释以字符序列开始,并在行尾// 停止。
一般注释以字符序列开始,/* 并以第一个后续字符序列停止*/。
注释不能在符文或 字符串文字或注释内部启动。不包含换行符的一般注释就像一个空格。任何其他评论都像换行。

标识符

标识符定义了程序种的主要操作实体,如变量和类型。标识符由一个或多个字母和数字组成。标识符中的第一个字符必须是一个字母。

identifier = letter { letter |unicode_digit }

a
_x9
ThisVariableIsExported
αβ

一些标识符是预先声明的。

关键词

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

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

以下字符序列表示运算符,分隔符和其他特殊令牌:

  • & += &= && == !=( )
  • | -= |= || < <= [ ]
  • ^ *= ^ = < - > >= { }
    ...

切片类型

切片是底层数组的连续片段的描述符,并提供对该阵列中编号序列的元素的访问。切片类型表示其元素类型的所有数组片段的集合。未初始化的片段的值为nil。

SliceType =“[”“]” ElementType。

像阵列一样,切片是可索引的并具有长度。切片的长度s可以通过内置函数发现 len; 与数组不同,它可能会在执行过程中发生变化。这些元素可以通过整数索引 0到len(s)-1。给定元素的切片索引可能小于底层数组中相同元素的索引。

一旦初始化,一个切片总是与一个保存其元素的底层数组相关联。因此,切片与其阵列和同一阵列的其他切片共享存储; 相比之下,不同的数组总是表示不同的存储。

切片下面的阵列可以延伸超过切片的末端。的容量是该程度的量度:它是切片并超出片的阵列的长度的长度的总和; 可以通过从原始切片切片一个新的片段来创建直到该容量 的片段。a可以使用内置函数发现切片的容量cap(a)。

给定元素类型的新的初始化切片值T使用内置函数进行make,该函数 采用切片类型和指定长度和可选容量的参数。创建的切片make始终分配返回的切片值所参考的新的隐藏数组。也就是执行

make([] T,长度,容量)

生成与分配数组相切的切片 ,因此这两个表达式是等价的:

make([] int,50,100)
new([100] INT)[0:50]

像序列一样,片段总是一维的,但是可以构成更高维度的对象。通过阵列阵列,内部阵列通过构造总是相同的长度; 然而,对于切片(或切片阵列),内部长度可能会动态变化。此外,内部切片必须单独初始化。

结构体

一个结构体是一个命名元素的序列,称为字段,每一个都有一个名称和一个类型。字段名称可以被明确指定(IdentifierList)或隐式(AnonymousField)。在结构体中,非空白字段名称必须是唯一的。

StructType =“struct”“{”{ FieldDecl “;” }“}”。
FieldDecl =(IdentifierList Type | AnonymousField)[ Tag ]。
AnonymousField = [“*”] TypeName。
Tag = string_lit。
//一个空结构。
struct {}

//具有6个字段的结构。
struct {

x,y int
你float32
_ float32 // padding
A * [] int
F func()

}

声明为类型但没有显式字段名称的字段是匿名字段,也称为嵌入字段或类型在struct中的嵌入。必须将嵌入式类型指定为类型名称T或指向非接口类型名称的指针*T,并且T本身可能不是指针类型。不合格的类型名称作为字段名称。

//具有类型T1,* T2,P.T3和* P.T4的四个匿名字段的结构
struct {

T1 //字段名称为T1
* T2 //字段名称为T2
P.T3 //字段名称为T3
* P.T4 //字段名称为T4
x,y int //字段名称是x和y

}

以下声明是非法的,因为字段名称在结构类型中必须是唯一的:

struct {

T //与匿名字段* T和* PT冲突
* T //与匿名字段T和* PT冲突
* PT //与匿名字段T和* T冲突

}

如果是表示该字段或方法的合法选择器,则 在结构体中的匿名字段的 字段或方法 称为“ 升级”。
推广字段的行为像一个结构体的普通字段,除了它们不能用作结构体的复合文字中的字段名称 。
给定一个struct类型S和一个类型T,在struct的方法集中包含了提升的方法,如下所示:

如果S包含一个匿名字段T的方法设置的S ,并S都包括推进与接收器的方法 T。方法集S还包括具有接收者的促销方法*T。
如果S包含一个匿名字段T,方法集S和S两个包括推进与接收器的方法T或 *T。
字段声明后面可以有一个可选的字符串文字标记,它可以成为相应字段声明中所有字段的属性。空标签字符串相当于缺少的标签。标签通过反射界面可见, 并参与结构体的类型标识,但是会被忽略。

struct {

x,y float64 “”//空标签字符串就像一个不存在的标签
namestring “允许任何字符串作为标签”
_ [4] byte“ceci n'est pas un champ de structure”

}

//与TimeStamp协议缓冲区对应的结构。
//标签字符串定义协议缓冲区字段号;
//他们遵循反射包所概述的惯例。
struct {

microsec uint64`protobuf:“1”`
serverIP6 uint64`protobuf:“2”`

}

指针类型

指针类型表示给定类型的变量的所有指针集,称为指针的基本类型。未初始化的指针的值为nil。

PointerType =“*” BaseType。
BaseType = Type。
*Point

  • [4]int

接口类型

一个接口类型指定一个方法集称为其接口。接口类型的变量可以存储任何类型的值,其方法集是接口的任何超集。据说实现这种类型 的接口。接口类型的未初始化变量的值为nil。

InterfaceType =“interface”“{”{ MethodSpec “;” }“}”。
MethodSpec = MethodName Signature | InterfaceTypeName。
MethodName = identifier。
InterfaceTypeName = TypeName。
与所有方法集一样,在接口类型中,每个方法必须具有 唯一的 非空白名称。

//一个简单的文件界面
interface {

Read(b Buffer) bool
Write(b Buffer) bool
Close()

}

多个类型可以实现一个接口。例如,如果两个类型S1并且S2 设置方法

func(p T)Read(b Buffer)bool {return ...}
func(p T)Write(b Buffer)bool {return ...}
func(p T)Close(){...}

其中T代表任何一个S1或S2),则该File接口由两者S1实现 S2,并且不管其他方法 S1以及S2可能具有或共享什么。

类型实现包括其方法的任何子集的任何接口,并且因此可以实现几个不同的接口。例如,所有类型都实现空接口:

interface{}

类似地,考虑这个接口规范,它出现在一个类型声明中 以定义一个接口Locker:

type Locker interface {

Lock()
Unlock()

}

如果S1和S2都实现了该接口

func(p T)Lock(){...}
func(p T)解锁(){...}

它们实现了Locker接口以及File接口。
接口T可以使用(可能是合格的)接口类型名称E代替方法规范。这就是所谓的 嵌入界面E中T; 它将所有(导出和未导出)方法添加E到接口 T。

type ReadWriter interface {

Read(b Buffer) bool
Write(b Buffer) bool

}

type File interface {

ReadWriter  // same as adding the methods of ReadWriter
Locker      // same as adding the methods of Locker
Close()

}

type LockedFile interface {

Locker
File        // illegal: Lock, Unlock not unique
Lock()      // illegal: Lock not unique

}

接口类型T可能不嵌入自身或循环嵌套自身。

// illegal: Bad cannot embed itself
type Bad interface {

Bad

}

// illegal: Bad1 cannot embed itself using Bad2
type Bad1 interface {

Bad2

}
type Bad2 interface {

Bad1

}

map类型

map是一种类型的无序组元素,称为元素类型,由另一类型的一组唯一键索引,称为密钥类型。未初始化地图的值为nil。

MapType =“map”“[” KeyType “]” ElementType。
KeyType = Type。

的比较运算符 ==和!=必须为键类型的操作数被完全定义; 因此,键类型不能是函数,映射或切片。如果密钥类型是接口类型,则必须为动态密钥值定义这些比较运算符; 失败会导致运行时间的恐慌。

map[string]int
map[*T]struct{ x, y float64 }
map[string]interface{}

map元素的数量称为其长度。对于map m,可以使用内置函数获得它len ,并可能在执行期间更改。可以在执行期间使用分配添加元素,并使用 索引表达式检索 ; 它们可以用delete内置功能删除 。

使用内置函数make创建一个新的空 map,该函数将地图类型和可选的容量提示作为参数:

make(map[string]int)
make(map[string]int, 100)

初始容量不受其大小的限制:map增长以适应其中存储的项目数量,但nil map 外。一个nil map相当于不同之处在于可以添加没有元素的空映射。

Channel管道类型

管道提供了一种机制 同时执行功能 通过通信 发送和 接收 一个指定的元素类型的值。未初始化频道的值为nil。

ChannelType =(“chan”|“chan”“< - ”|“< - ”“chan”)ElementType。

可选<-操作符指定通道方向, 发送或接收。如果没有给定方向,通道是 双向的。频道可能被限制只发送或仅通过转换或转让接收 。

chan T //可用于发送和接收T类型的值
chan < - float64 //只能用于发送float64s
<-chan int //只能用于接收int

chan < - chan int //与chan相同< - (chan int)
chan < - <-chan int //与chan < - (<-chan int)相同
<-chan <-chan int //与<-chan(<-chan int)相同
chan(<-chan int)

可以使用内置函数创建新的初始化通道值 make,该函数将通道类型和可选容量作为参数:

make(chan int,100)

元素数量的容量设置通道中缓冲区的大小。如果容量为零或不存在,则信道是无缓冲的,并且仅当发送器和接收器都准备就绪时,通信才能成功。否则,如果缓冲区未满(发送)或不为空(接收),则通道被缓冲并且通信成功而不阻塞。一个nil频道从未准备好进行通信。
通道可以通过内置功能关闭close。接收运营商的多值分配形式 报告在通道关闭前是否发送了接收到的值。

单个通道可用于 发送语句, 接收操作和对内置函数的调用 cap以及 len 任何数量的goroutine而不进一步同步。频道作为先进先出队列。例如,如果一个goroutine在一个通道上发送值,另一个goroutine接收它们,则按发送的顺序接收这些值。

类型变换

在以下这些情况下, 值x可分配给类型的变量T (“ x可分配给T”):

x的类型是相同的T。
x的类型V,并T具有相同的 底层类型,至少有一个V 或T不是命名类型。
T是一种接口类型和 x 实现方式 T。
x是双向通道值,T是通道类型 x的类型V,T具有相同的元素类型,并且至少有一个V或T不是命名类型。
x是预先声明的标识符nil,T 是指针,功能,切片,地图,通道或界面类型。
x是由类型值表示的无类型常数T。

代码块

一个块是匹配括号内可能是空的一系列声明和语句。

Block =“{” StatementList “}”。
StatementList = { Statement “;” }。

除了源代码中的显式块之外,还有一些隐式块:

在全局块包含所有围棋源文本。
每个包都有一个包含该包的所有Go源文本的包块。
每个文件都有一个包含该文件中所有Go源文本的文件块。
每个“if”, “for”和 “switch” 语句被认为是在其自己的隐式块中。
“switch” 或“select”语句中的每个子句用作隐式块。
代码块嵌套和影响范围。

IOTA

在常量声明中,预先声明的 iota标识符表示连续的无类型整数 常量。每当保留字const 出现在源中并在每个ConstSpec之后递增,它将重置为0 。它可以用来构造一组相关的常量:

const(// iota将重置为0

c0 = iota // c0 == 0
c1 = iota // c1 == 1
c2 = iota // c2 == 2

const(// iota将重置为0

a = 1 << iota // a == 1
b = 1 << iota // b == 2
c = 3 // c == 3(iota不使用但仍然增加)
d = 1 << iota // d == 8

const(// iota将重置为0

u = iota * 42 // u == 0(无类型整数常量)
v float64 = iota * 42 // v == 42.0(float64 constant)
w = iota * 42 // w == 84(无类型整数常数)

const x = iota // x == 0(iota已被重置)
const y = iota // y == 0(iota已被重置)

在一个ExpressionList中,每个值的值iota相同,因为它只在每个ConstSpec之后递增:

const(

bit0,mask0 = 1 << iota,1 << iota  -  1 // bit0 == 1,mask0 == 0
bit1,mask1 // bit1 == 2,mask1 == 1
_,_ //跳过iota == 2
bit3,mask3 //位3 == 8,mask3 == 7

最后一个例子利用最后一个非空表达式列表的隐式重复。

类型声明

类型声明将标识符(类型名称)绑定到与现有类型具有相同底层类型的新类型,并为新类型定义为现有类型定义的操作。新的类型是不同的,从现有的类型。

TypeDecl =“type”(TypeSpec |“(”{ TypeSpec “;”}“)”)。
TypeSpec = identifier 类型。
type IntArray [16]int

type (

Point struct{ x, y float64 }
Polar Point

)

type TreeNode struct {

left, right *TreeNode
value *Comparable

}

type Block interface {

BlockSize() int
Encrypt(src, dst []byte)
Decrypt(src, dst []byte)

}

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

// A Mutex is a data type with two methods, Lock and Unlock.
type Mutex struct { /* Mutex fields */ }
func (m Mutex) Lock() { / Lock implementation */ }
func (m Mutex) Unlock() { / Unlock implementation */ }

// NewMutex has the same composition as Mutex but its method set is empty.
type NewMutex Mutex

// The method set of the base type of PtrMutex remains unchanged,
// but the method set of PtrMutex is empty.
type PtrMutex *Mutex

// The method set of *PrintableMutex contains the methods
// Lock and Unlock bound to its anonymous field Mutex.
type PrintableMutex struct {

Mutex

}

// MyBlock is an interface type that has the same method set as 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)

}

变量声明

变量声明创建一个或多个变量,将对应的标识符绑定到它们,并给出每个变量的类型和初始值。

VarDecl =“var”(VarSpec |“(”{ VarSpec “;”}“)”)。
VarSpec = IdentifierList(Type [“=” ExpressionList ] |“=”

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] // map lookup; only interested in "found"

如果给出了一个表达式列表,变量将按照分配规则的表达式进行初始化。否则,每个变量被初始化为其零值。

如果存在类型,则给出每个变量的类型。否则,给定每个变量在赋值中相应的初始化值的类型。如果该值是一个无类型常数,首先 转换到其默认类型 ; 如果它是一个无类型的布尔值,则首先将其转换为类型bool。预先声明的值nil不能用于初始化没有显式类型的变量。

var d = math.Sin(0.5)// d是float64
var i = 42 //我是int
var t,ok = x。(T)// t是T,ok是bool
var n = nil // illegal

实现限制:如果变量永远不被使用,编译器可能会在函数体内声明一个变量是非法的。

短变量声明

一个简短的变量声明使用语法:

ShortVarDecl = IdentifierList “:=” ExpressionList。

它是 使用初始化器表达式但不包含类型的常规变量声明的缩写:

“var”IdentifierList = ExpressionList。
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)// redeclares offset
a,a:= 1,2 // illegal:如果在其他地方声明了一个或没有新变量的双重声明

短变量声明只能在函数内部出现。在某些上下文中,例如 “if”, “for”或 “switch”语句的初始化器,它们可以用于声明本地临时变量。

函数声明

函数声明将一个标识符(函数名称)绑定到一个函数。
``
FunctionDecl =“func” FunctionName(Function | Signature)。
FunctionName = identifier。
功能 = 签名 功能。
FunctionBody = Block。

如果函数的签名声明结果参数,则函数体的语句列表必须以终止语句结尾。

func IndexRune(s string, r rune) int {
for i, c := range s {
if c == r {
return i
}
}
// invalid: missing return statement
}

函数声明可以省略身体。这样的声明提供了Go外部执行的功能的签名,例如汇编程序。

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

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

方法声明

一种方法是具有接收器的功能。方法声明将标识符,方法名称绑定到方法,并将该方法与接收方的基类型相关联。

MethodDecl =“func” Receiver MethodName(Function | Signature)。
Receiver = 参数。

接收方通过方法名称之前的额外参数部分指定。该参数部分必须声明单个非可变参数,接收器。它的类型必须是形式T或*T(可能使用括号),其中T是一个类型名称。表示的类型T称为接收者基类型 ; 它不能是一个指针或接口类型,它必须在与该方法相同的包中声明。该方法被认为是结合到基底的类型和方法名唯一内是可见的选择器类型T 或*T。

非空白接收者标识符在方法签名中必须是 唯一的。如果接收方的值未在方法体内引用,则其声明中可能会省略其标识符。这一般同样适用于功能和方法的参数。

对于基类型,与其绑定的方法的非空名称必须是唯一的。如果基类型是一个结构类型,则非空白方法和字段名必须是不同的。

给定类型Point,声明

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
}

使用接收器类型 绑定方法Length和基类型。 Scale*PointPoint

方法的类型是接收器作为第一个参数的函数的类型。例如,该方法Scale具有类型

func(p *点,因子float64)

但是,以这种方式声明的函数不是一种方法。

表达式

表达式通过将运算符和函数应用于操作数来指定值的计算。

操作数

操作数表示表达式中的基本值。一个操作数可以是一个文字,一个(可能是合格的)非空白标识符,表示一个 常量, 变量或 函数,一个产生函数的方法表达式或一个括号化的表达式。

的空白标识符可能显示为仅一个上的左手侧的操作数分配。

operand = 文字 | OperandName | MethodExpr | “(” 表达 “)”。
Literal = BasicLit | CompositeLit | FunctionLit。
BasicLit = int_lit | float_lit | imaginary_lit | rune_lit | string_lit。
OperandName = identifier | QualifiedIdent。

合格标识符

合格的标识符是具有包名前缀的标识符。软件包名称和标识符都不能为 空。

QualifiedIdent = PackageName “。” 标识符。

合格标识符访问必须导入的不同包中的标识符。必须在该包的包块中导出并声明该标识符。

math.Sin //表示包数学中的Sin函数

复合类型

复合类型为结构,数组,切片和地图构造值,并在每次评估时创建一个新值。它们由文字的类型组成,后跟一个括号绑定的元素列表。每个元素可以可选地在相应的键之前。

CompositeLit = LiteralType LiteralValue。
LiteralType = StructType | ArrayType | “[”“...”“]” ElementType |
SliceType | MapType | TypeName。
LiteralValue =“{”[ ElementList [“,”]]“}”。
ElementList = KeyedElement {“,” KeyedElement }“。
KeyedElement = [ Key “:”] 元素。
Key = FieldName | 表达 | 文字值。
FieldName = 标识符。
Element = Expression | 文字值。

LiteralType的底层类型必须是一个struct,array,slice或map类型(语法强制执行此约束,除非该类型以TypeName形式给出)。元素和键的类型必须可分配 给文字类型的相应字段,元素和键类型; 没有额外的转换。关键字被解释为结构文字的字段名称,数组和片文本的索引以及地图文字的关键字。对于地图文字,所有元素必须有一个键。指定具有相同字段名称或常量键值的多个元素是一个错误。

对于结构文字,以下规则适用:

  • 键必须是在struct类型中声明的字段名称。
  • 不包含任何键的元素列表必须按照声明字段的顺序列出每个结构域的元素。
  • 如果任何元素有一个键,每个元素都必须有一个键。
  • 包含键的元素列表不需要每个结构域的元素。省略的字段获得该字段的零值。
  • 文字可以省略元素列表; 这样一个文字评估它的类型的零值。
  • 为属于不同包的结构体的未导出字段指定元素是一个错误。

每个元素都有一个关联的整数索引,标记其在数组中的位置。
具有键的元素使用键作为其索引。关键字必须是由值类型表示的非负常数int; 如果它是类型,它必须是整数类型。
没有键的元素使用前一个元素的索引加一个。如果第一个元素没有键,其索引为零。
以复合文字的地址生成一个指向使用文字值初始化的唯一变量的指针。

var pointer * Point3D =&Point3D {y:1000}

数组文字的长度是文字类型中指定的长度。如果在文字中提供的元素少于长度,则将丢失的元素设置为数组元素类型的零值。在数组的索引范围之外提供索引值的元素是一个错误。该符号...指定等于最大元素索引加一的数组长度。

buffer:= [10] string {} // len(buffer)== 10
intSet:= [6] int {1,2,3,5} // len(intSet)== 6
days:= [...] string {“Sat”,“Sun”} // len(days)== 2

切片文字描述整个底层数组文字。因此,片段文字的长度和容量是最大元素索引加1。一个片文字有形式

[] T {x1,x2,... xn}

并且是应用于数组的切片操作的缩写:
```�
tmp:= [n] T {x1,x2,... xn}
tmp [0:n]n

在数组,切片或地图类型T的复合文字中,如果元素或键类型与元素或键类型相同,则本身是复合文字的元素或地图键可能会删除相应的文字类型T。类似地,作为复合文字地址&T的元素或键可以在元素或键类型的时候消除*T。

[...] Point {{1.5,-3.5},{0,0}} //与[...] Point {Point {1.5,-3.5},Point {0,0}}相同}
[] [] int {{1,2,3},{4,5}} //与[] [] int {[] int {1,2,3},[] int {4,5}}相同)
[] [] {{{0,1},{1,2}}} //与[] [] Point {[] Point {Point {0,1},Point {1,2}}}
map [string] Point {“orig”:{0,0}} //与map相同[string] Point {“orig”:Point {0,0}}
map [Point] string {{0,0}:“orig”} //与map相同[Point] string {Point {0,0}:“orig”}

当使用LiteralType的TypeName形式的复合文字显示为关键字和“if”,“for”或“switch”语句的块的开头大括号之间的操作数时,会出现 解析歧义,而复合文字为不包括在括号,方括号或大括号中。在这种罕见的情况下,文字的大括号被错误地解释为引入语句的一个。要解决歧义,复合文字必须出现在括号中。
``
if x ==(T {a,b,c} [i]){...}
if(x == T {a,b,c} [i]){...}

如果类型x是一个命名的指针类型,并且(*x).f是一个表示一个字段(而不是一个方法)的有效的选择器表达式,x.f则为缩写(*x).f。
在所有其他情况下,x.f是非法的。
如果x是指针类型,并且具有值 nil并x.f表示结构域,则分配或评估x.f 将导致运行时紧急。
如果x是接口类型并具有该值 nil,则调用或 评估该方法x.f 将导致运行时的紧急情况。

索引表达式

形式的主要表现形式

a[x]

表示数组的元素,指向数组,slice,string或map的a索引的指针x。该值x分别称为索引或地图键。以下规则适用:

如果a不是map:

  • 索引x必须是整数类型或无类型; 它是在范围如果0 <= x < len(a),否则它是超出范围
    一个恒定索引必须是通过type的值是非负的和表示的int
    为a的数组类型 A:
  • 一个恒定索引必须是在范围
  • 如果x在运行时超出范围,则会发生运行时紧急
  • a[x]是索引处的数组元素x,其类型 a[x]是元素类型A
    对于指向数组类型a的指针:
  • a[x] 是速记 (*a)[x]
    对于a的片类型 S:
  • 如果x在运行时超出范围,则会发生运行时紧急
  • a[x]是索引处的切片元素x,其类型 a[x]是元素类型S
    对于a的字符串类型:
  • 一个恒定索引必须是在范围内,如果该字符串a也是恒定
  • 如果x在运行时超出范围,则会发生运行时紧急
  • a[x]在索引的非恒定字节值x和类型 a[x]就是byte
  • a[x] 可能不会分配给
    对于a的地图类型 M:
  • x的类型必须可以 分配 给键的类型M
  • 如果地图包含带有键的条目x, a[x]则是带有键的地图值,x 类型a[x]是值类型M
  • 如果地图是nil或不包含这样的条目, a[x]则为 值类型的零值M
    否则a[x]是非法的。

在特殊表单 的分配或初始化中 使用a的类型 的地图上的索引表达式map[K]V

v,ok = a [x]
v,ok:= a [x]
var v,ok = a [x]
var v,ok T = a [x]

产生一个额外的无类型布尔值。的值ok是 true如果该键x存在于地图,和 false其它。

分配给nil地图的元素会导致 运行时的紧急情况。

切片表达式

Slice表达式从字符串,数组,指向数组或切片的指针构造子字符串或切片。有两个变体:一个指定一个低和高边界的简单形式,以及一个完整的表单,也指定了对容量的约束。

简单的切片表达式

对于字符串,数组,指向数组或切片的指针a,主表达式

a[low:high]

构造子字符串或切片。的索引 low和 high操作数的选择哪些元素a显示在结果中。结果具有从0开始的长度等于high - 的 索引 low。切片数组后a

a:= [5] int {1,2,3,4,5}
s:= a [1:4]

切片s有类型[]int,长度3,容量4和元素

s [0] == 2
s [1] == 3
s [2] == 4

为了方便,可以省略任何索引。缺少的low 索引默认为零; 缺少的high索引默认为切片操作数的长度:

a[2:] //与[2:len(a)]相同]
a[:3] //与[0:3]相同
a[:] //与[0:len(a)]相同]

如果a是指向数组的指针,a[low : high]则为缩写 (*a)[low : high]。

对于数组或字符串,如果 <= <= <= ,则索引在范围内,否则超出范围。对于切片,上限索引是切片的容量而不是长度。甲恒定索引必须是通过type的值是非负的和表示的 ; 对于数组或常量字符串,常数索引也必须在范围内。如果两个指标都不变,则必须满足。如果索引在运行时超出范围,则会发生运行时紧急。 0lowhighlen(a)cap(a)intlow <= high

除非类型字符串外,如果切片操作数是字符串或片,则切片操作的结果是与操作数相同类型的非常量值。对于无类型的字符串操作数,结果是类型的非常量值string。如果切片操作数是数组,则它必须可寻址 ,并且切片操作的结果是与数组具有相同元素类型的切片。

如果有效切片表达式的切片操作数是nil切片,则结果为nil切片。否则,结果与操作数共享其底层数组。

全切片表达式

对于数组,指向数组或切片a(而不是字符串)的指针,是主表达式

a [low:high:max]

构造相同类型的切片,并且具有与简单切片表达式相同的长度和元素a[low : high]。此外,它通过设置它来控制结果切片的容量max - low。只有第一个索引可以省略; 它默认为0.切片数组后a

a:= [5] int {1,2,3,4,5}
t:= a [1:3:5]

切片t具有类型[]int,长度2,容量4和元素

t [0] == 2
t [1] == 3

对于简单的切片表达式,如果a是指向数组的指针, a[low : high : max]则为缩写(*a)[low : high : max]。如果切片操作数是数组,则必须是可寻址的。

如果它们超出范围,则 指数在范围内。甲恒定索引必须是通过type的值是非负的和表示的 ; 对于数组,常数索引也必须在范围内。如果多个索引是常数,则存在的常数必须在相对于彼此的范围内。如果索引在运行时超出范围,则会发生运行时紧急。 0 <= low <= high <= max <= cap(a)int

断言

对于表达式x的接口类型 和类型T,主表达式

X.(T)

断言x不是nil ,存储的值x是类型T。该符号x.(T)称为类型断言。
更精确地,如果T不是一个接口类型,x.(T)断言,动态型的x是相同 的类型T。在这种情况下,T必须实现(接口)类型x; 否则类型断言是无效的,因为不可能x 存储类型的值T。如果T是接口类型,则x.(T)断言实现x接口的动态类型T。

如果类型断言成立,表达式的值是存储的值x,其类型是T。如果类型断言为false,则会发生运行时紧急情况。换句话说,即使动态类型的x 只是在运行时是已知的类型,x.(T)被称为是T在一个正确的程序。

var x interface {} = 7 // x具有动态类型int和值7
i:= x。(int)//我有类型int和值7

type I interface {m()}

func f(y I){
s:= y。(string)// illegal:string不实现I(缺少方法m)
r:= y。(io.Reader)// r具有类型io.Reader,y的动态类型必须实现I和io.Reader
...
}

在特殊表单 的分配或初始化中 使用的类型断言
```n
v,ok = x.(T)
v,ok:= x.(T)
var v,ok = x.(T)
var v,ok T1 = x.(T)
产生一个额外的无类型布尔值。值ok是true 如果断言成立。否则,它是false和值v是零值的类型T。在这种情况下不会发生运行时恐慌。

调用
给定一个f函数类型 的表达式F,

f(a1,a2,... an)

调用f带参数a1, a2, … an。除了一个特殊情况,参数必须是可以分配给参数类型的单值表达式 , F并在调用函数之前进行求值。表达式的类型是结果类型F。方法调用是相似的,但是方法本身被指定为方法的接收器类型的值的选择器。

math.Atan2(x,y)//函数调用
var pt * Point
pt.Scale(3.5)//方法调用接收器pt

在函数调用中,函数值和参数 按照通常的顺序进行计算。评估后,调用的参数将通过值传递给函数,被调用函数开始执行。当函数返回时,函数的返回参数通过值传递回调用函数。

调用nil函数值会导致运行时的紧急情况。

作为特殊情况,如果函数或方法的返回值 g在数量上相等并且可以单独分配给另一个函数或方法的参数 f,则在 将返回值绑定到顺序的参数后 ,调用将调用。调用必须不包含调用以外的参数,并且必须至少有一个返回值。如果有一个最终参数,那么它将被分配给定义参数赋值后的返回值。

func Split(s string,pos int)(string,string){
return s [0:pos],s [pos:]
}

func Join(s,t string)string {
return s + t
}

if Join(Split(value,len(value)/ 2))!= value {
log.Panic(“test failed”)
}

x.m()如果方法集 (类型)x包含m且参数列表可以分配给参数列表, 方法调用是有效的m。如果x是寻址和&x的方法集包含m,x.m()是简写(&x).m():

var p Point
p.Scale(3.5)

没有明确的方法类型,没有方法文字。

变长参数传递...参数

如果f是可变参数与最终的参数p类型的...T,那么内f 的类型p是相当于类型[]T。如果f没有实际参数被调用p,则传递给的p值为nil。否则,传递的值是类型的新切片[]T用新的底层数组,其连续元素是实际的参数,其中所有必须分配 到T。因此,切片的长度和容量是p每个呼叫站点绑定的参数数量,并且可能不同。

给定功能和调用

func Greeting(prefix string, who ...string)
Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")

在内部Greeting,who将有nil第一个调用的值 , []string{"Joe", "Anna", "Eileen"}在第二个。

如果最后一个参数可以分配给切片类型[]T,则...T如果参数后面跟着,则它可以作为参数的值不变地传递...。在这种情况下,不会创建新的切片。

给予切片s和调用

s := []string{"James", "Jasmine"}
Greeting("goodbye:", s...)

运算符优先

一元运算符具有最高优先级。由于 ++和--运算符形成语句,而不是表达式,它们落在运算符层次结构之外。因此,声明与之*p++相同(*p)++。

二进制运算符有五个优先级。乘法运算符绑定最强,后跟加法运算符,比较运算符&&(逻辑与)和最后||(逻辑或):

优先运算符

5 * /%<< >>&&^
4 + - | ^
3 ==!= <<=>> =
2 &&
1 ||

具有相同优先级的二进制运算符从左到右。例如,x / y * z是一样的(x / y) * z。

X
23 + 3 * x [i]
x <= f()
^ a >> b
f()|| G()
x == y + 1 && <-chanPtr> 0

整数溢出

为无符号整数值,所述操作+, -,*,和<<被计算模2 Ñ,其中Ñ为的比特宽度的无符号整数的类型。松散地说,这些无符号整数运算在溢出时丢弃高位,程序可能会依赖于“环绕”。

对于有符号整数,操作+, -,*,和<<可以合法溢出并且将所得值存在并且确定地由带符号整数,操作,和它的操作数定义。由于溢出而引起异常。在不发生溢出的假设下,编译器可能无法优化代码。例如,它可能不认为这x < x + 1是永远是真的。

浮点运算符

对于浮点数和复数, +x是相同的x,而是-x否定的x。没有超出IEEE-754标准规定浮点或零除零的结果。是否发生运行时恐慌 是实现特定的。

字符串连接

字符串可以使用+运算符或+=赋值运算符进行连接:

s:=“hi”+ string(c)
s + =“�and good bye”

字符串加法通过连接操作数创建一个新的字符串。

比较运算符

比较运算符比较两个操作数,并产生一个无类型的布尔值。

==相等
!=不相等
<少
<=小于或等于

更大
=大于或等于

在任何比较中,第一个操作数必须分配 给第二个操作数的类型,反之亦然。

等式运算符==和!=应用到操作数是可比的。排序运营商<,<=,>和>= 适用于那些操作数排序。这些术语和比较结果定义如下:

  • 布尔值是可比的。如果他们或者都两个布尔值相等 true或两者false。
    整数值可以和通常的方式进行排序。
    浮点数值可以与IEEE-754标准定义相当且有序。
    复杂的值是可比的。两个复数值u和v是如果两个相等的real(u) == real(v)和 imag(u) == imag(v)。
  • 字符串值是可比较的,按字节顺序排序。
  • 指针值是可比的。如果两个指针的值指向相同的变量或两者都具有值,则两个指针值相等nil。指向不同零大小变量的指针可能相同也可能不相等。
  • 通道值是可比的。如果两个通道值是通过相同的调用创建的,make 或者两者都具有值,则两个通道值相等 nil。
  • 接口值是可比的。两个接口值相等,如果它们具有相同的动态类型和等于动态值或如果两者都具有价值nil。
  • 当x类型X值t类似T且实现时,非接口类型的值和接口类型的值X是可 X比较的T。如果t动态类型X 与t动态值相同,则动态值相等x。
  • 如果它们的所有领域都是可比较的,则结构值是可比较的。如果相应的非空白字段相等,则两个结构值相等。
  • 如果数组元素类型的值可比较,则数组值可比较。如果两个数组的相应元素相等,则两个数组值相等。
    具有相同动态类型的两个接口值的比较会导致运行时的紧急情况,如果该类型的值不可比较。此行为不仅适用于直接接口值比较,还适用于将接口值或结构体的数组与接口值字段进行比较时。

切片,地图和功能值不可比。然而,作为特殊情况,可以将片,地图或函数值与预先声明的标识符进行比较nil。指针,通道和接口值的nil 比较也可以从上面的一般规则得到。

const c = 3 < 4 // c is the untyped boolean constant true

type MyBool bool
var x, y int
var (
// The result of a comparison is an untyped boolean.
// The usual assignment rules apply.
b3 = x == y // b3 has type bool
b4 bool = x == y // b4 has type bool
b5 MyBool = x == y // b5 has type MyBool
)

转换

转换是表单的表达式T(x) ,T它是一种类型,x是可以转换为类型的表达式T。

Conversion = Type "(" Expression [ "," ] ")" .

如果类型与操作者启动*或<-,或者如果类型以关键字开头func ,也没有结果列表,必须要加上括号必要时以避免歧义:

*Point(p) // same as (Point(p))
(Point)(p) // p is converted to *Point
<-chan int(c) // same as <-(chan int(c))
(<-chan int)(c) // c is converted to <-chan int
func()(x) // function signature func() x
(func())(x) // x is converted to func()
(func() int)(x) // x is converted to func() int
func() int(x) // x is converted to func() int (unambiguous)

恒定值x可以被转换成键入T在任何这些情况中:

与字符串类型的转换

将有符号或无符号整数值转换为字符串类型会产生包含整数的UTF-8表示形式的字符串。超出有效Unicode代码点范围的值将转换为"\uFFFD"。

string('a')//“a”
string(-1)//“\ ufffd”==“\ xef \ xbf \ xbd”
string(0xf8)//“\ u00f8”==“ø”==“\ xc3 \ xb8”
键入MyString字符串
MyString(0x65e5)//“\ u65e5”==“日”==“\ xe6 \ x97 \ xa5”
将字节片段转换为字符串类型会产生一个字符串,其连续字节是片段的元素。
string([] byte {'h','e','l','l','\ xc3','\ xb8'})//“hellø”
string([] byte {})//“”
string([] byte(nil))//“”

键入MyBytes []字节
string(MyBytes {'h','e','l','l','\ xc3','\ xb8'})//“hellø”
将一段符号转换为字符串类型会产生一个字符串,该字符串是转换为字符串的单个符文值的并置。
string([] rune {0x767d,0x9d6c,0x7fd4})//“\ u767d \ u9d6c \ u7fd4”==“白鹏翔”
string([] rune {})//“”
string([] rune(nil))//“”

键入MyRunes []符文
string(MyRunes {0x767d,0x9d6c,0x7fd4})//“\ u767d \ u9d6c \ u7fd4”==“白鹏翔”

将字符串类型的值转换为字节类型的片段会产生一个切片,其连续元素是字符串的字节。

[] byte(“hellø”)// [] byte {'h','e','l','l','\ xc3','\ xb8'}
[] byte(“”)// [] byte {}

MyBytes(“hellø”)// [] byte {'h','e','l','l','\ xc3','\ xb8'}

将字符串类型的值转换为符号类型的片段将生成包含字符串的各个Unicode代码点的切片。

[] rune(MyString(“白鹏翔”))// [] rune {0x767d,0x9d6c,0x7fd4}
[] rune(“”)// [] rune {}

MyRunes(“白鹏翔”)// [] rune {0x767d,0x9d6c,0x7fd4}

printFloat64(i)//我的类型是float64

case func(int)float64:

printFunction(i)//我的类型是func(int)float64

case bool,string:

printString(“type is bool or string”)//我的类型是x(interface {})

默认:

printString(“不知道类型”)//我的类型是x(interface {})

}
可以重写:

v:= x // x被精确评估一次
如果v == nil {

i:= v //我的类型是x(interface {})
printString(“x is nil”)

} else if i,isInt:= v。(int); isInt {

printInt(i)//我的类型是int

} else if i,isFloat64:= v。(float64); isFloat64 {

printFloat64(i)//我的类型是float64

} else if i,isFunc:= v。(func(int)float64); isFunc {

printFunction(i)//我的类型是func(int)float64

} else {

_,isBool:= v。(bool)
_,isString:= v。(string)
如果isBool || isString {
    i:= v //我的类型是x(interface {})
    printString(“type is bool or string”)
} else {
    i:= v //我的类型是x(interface {})
    printString(“不知道类型”)
}

}

Go语句
A“走出去”的语句开头的函数调用独立的控制并发线程,或执行的goroutine,相同的地址空间内。

GoStmt =“go” 表达式。
表达式必须是函数或方法调用; 它不能括号。对于表达式语句,内置函数的调用 受到限制。

函数值和参数 在调用goroutine中一样被评估,但与常规调用不同,程序执行不等待调用的函数完成。相反,函数在新的goroutine中开始独立执行。当函数终止时,其goroutine也终止。如果函数有任何返回值,则在函数完成时将被丢弃。

去服务器()
去func(ch chan < - bool){for {sleep(10); ch < - true; }} (C)
选择语句
“选择”语句选择一组可能的 发送或 接收操作中的 哪一个将继续进行。它看起来类似于 “switch”语句,但是这些情况都是指通信操作。

SelectStmt =“select”“{”{ CommClause }“}”。
CommClause = CommCase “:” StatementList。
CommCase =“case”(SendStmt | RecvStmt)| “默认”。
RecvStmt = [ ExpressionList “=”| IdentifierList “:=”] RecvExpr。
RecvExpr = 表达式。
具有RecvStmt的情况可以将RecvExpr的结果分配给一个或两个变量,这些变量可以使用短变量声明来声明 。RecvExpr必须是(可能是括号)的接收操作。最多可以有一个默认情况,它可能会出现在案例列表中的任何位置。

执行“select”语句可以在几个步骤中进行:

对于语句中的所有情况,在输入“select”语句时,接收操作的通道操作数和发送语句的通道和右侧表达式以源的顺序精确地计算一次。结果是一组要从中发送或发送的频道以及相应的值发送。无论选择哪个(如果有的话)通信操作进行,该评估中的任何副作用都将发生。具有短变量声明或赋值的RecvStmt左侧的表达式尚未被评估。
如果一个或多个通信可以进行,则可以通过统一的伪随机选择来选择可以进行的一个。否则,如果有默认情况,则选择该情况。如果没有默认情况,则“select”语句将阻塞,直到至少有一个通信可以继续。
除非选择的情况是默认情况,否则执行相应的通信操作。
如果所选案例是具有短变量声明或赋值的RecvStmt,则将评估左侧表达式并分配接收的值(或值)。
执行所选案例的语句列表。
由于nil频道上的通信无法继续进行,只能选择一个nil通道,而不需要默认情况块。

var a [] int
var c,c1,c2,c3,c4 chan int
var i1,i2 int
select {
case i1 = <-c1:
print(“received”,i1,“from c1 \ n”)
case c2 < - i2:
print(“sent”,i2,“to c2 \ n”)
case i3,ok:=(<-c3)://相同:i3,ok:= <-c3
if ok{
print(“received”,i3,“from c3 \ n”)
} else {
print(“c3已关闭\ n”)
}
case a [f()] = <-c4:
// 与...一样:
// case t:= <-c4
// a [f()] = t
default:
print(“no communication \ n”)
}

{//将随机的位序列发送到c
select {
case c < - 0://注意:没有声明,没有掉落,没有折叠的情况
case c < - 1:
}
}

选择{} //阻止永远
回报表
函数中的“返回”语句F终止执行F,并可选地提供一个或多个结果值。任何延迟的函数F 在F返回给其调用者之前执行。

ReturnStmt =“return”[ ExpressionList ]。
在没有结果类型的函数中,“return”语句不能指定任何结果值。

func noResult(){

返回

}
有三种方法可以从结果类型的函数返回值:

返回值或值可以在“return”语句中明确列出。每个表达式必须是单值的,并可分配 给函数结果类型的相应元素。
func simpleF()int {

返回2

}

func complexF1()(re float64,im float64){

返回-7.0,-4.0

}
“return”语句中的表达式列表可以是对多值函数的单个调用。效果就好像从该函数返回的每个值都分配给具有相应值的类型的临时变量,后跟一个列出这些变量的“return”语句,此时应用前一种情况的规则。
func complexF2()(re float64,im float64){

返回complexF1()

}
如果函数的结果类型指定了其结果参数的名称,则表达式列表可能为空。结果参数作为普通局部变量,函数可以根据需要为其分配值。“return”语句返回这些变量的值。
func complexF3()(re float64,im float64){

re = 7.0
im = 4.0
返回

}

func(devnull)Write(p [] byte)(n int,_ error){

n = len(p)
返回

}
无论如何声明它们,所有结果值都将在输入函数时初始化为其类型的零值。指定结果的“返回”语句在执行任何延迟函数之前设置结果参数。

实现限制:如果与结果参数具有相同名称的不同实体(常量,类型或变量)在返回位置的范围内,编译器可能会在“返回”语句中禁止空表达式列表 。

func f(n int)(res int,err error){

如果_,err:= f(n-1); err!= nil {
    return // invalid return statement:err is shadowed
}
返回

}
打破声明
“break”语句终止同一功能内最内层的 “for”, “switch”或 “select”语句的执行。

BreakStmt =“break”[ Label ]。
如果有标签,它必须是封闭的“for”,“switch”或“select”语句,这是执行终止的标签。

OuterLoop:

对于i = 0; 我<n; 我++ {
    对于j = 0; j <m; j ++ {
        切换[i] [j] {
        案例无
            状态=错误
            打破OuterLoop
        病例项目:
            状态=找到
            打破OuterLoop
        }
    }
}

继续发言
“继续” 语句在其post语句中开始下一次最内层“for”循环的迭代。“for”循环必须在同一个函数内。

ContinueStmt =“continue”[ Label ]。
如果有一个标签,它必须是一个封闭的“for”语句,这就是执行进度的那个。

RowLoop:

对于y,row:= range rows {
    对于x,data:= range row {
        如果data == endOfRow {
            继续RowLoop
        }
        row [x] = data + bias(x,y)
    }
}

Goto语句
“goto”语句将控件转移到具有相同功能中的相应标签的语句。

GotoStmt =“goto” 标签。
goto错误
执行“GOTO”语句不能造成任何变量生效 范围是不是已经在范围在跳转点。例如,这个例子:

goto L // BAD
v = = 3

L:
是错误的,因为跳到标签L跳过创建v。

块 外的“goto”语句不能跳转到该块内的标签。例如,这个例子:

如果n%2 == 1 {

goto L1

}
对于n> 0 {

F()
N--

L1:

F()
N--

}
是错误的,因为标签L1在“for”语句的块内,但goto不是。

落后声明
“fallthrough”语句将控制转移到表达式“switch”语句中的下一个case子句的第一个语句。它可能只能用作这样一个子句中的最后一个非空的语句。

FallthroughStmt =“fallthrough”。
延迟声明
“延迟”语句调用一个函数,其执行延迟到周围函数返回的时刻,这是因为周围的函数执行了一个返回语句,到达其函数体的末尾,或者因为相应的goroutine是惊慌。

DeferStmt =“延迟” 表达式。
表达式必须是函数或方法调用; 它不能括号。对于表达式语句,内置函数的调用 受到限制。

每次执行“延迟”语句时,调用的函数值和参数按照惯例进行 评估, 并重新保存,但实际的函数不被调用。相反,延迟函数在周围函数返回之前立即被调用,按照相反的顺序被推迟。如果延迟函数值计算为nil, 调用函数时执行紧急情况,而不是执行“延迟”语句。

例如,如果延迟函数是函数文字,并且周围的函数具有范围在文字中的命名结果参数,则延迟函数可以在返回结果参数之前访问和修改它们。如果延迟函数具有任何返回值,则在函数完成时将被丢弃。(另见有关处理恐慌的部分)

锁(L)
延迟解锁(l)//解锁在周围函数返回之前发生

//打印3 2 1 0,然后循环返回
对于i:= 0; 我<= 3; 我++ {

推迟fmt.Print(i)

}

// f返回1
func f()(result int){

推迟func(){
    结果++
}()
返回0

}
内置功能
内置函数是 预先声明的。它们被称为任何其他函数,但其​​中一些函数接受一个类型而不是一个表达式作为第一个参数。

内置函数没有标准的Go类型,因此它们只能出现在调用表达式中 ; 它们不能用作函数值。


对于通道c,内置函数close(c) 记录在通道上不会再发送更多值。如果c是仅接收通道,则是错误的。发送或关闭封闭的通道会导致运行时间的紧急。关闭nil通道也会导致运行时间的恐慌。调用close后,在接收到任何先前发送的值之后,接收操作将返回通道类型的零值,而不会阻塞。多值接收操作 返回接收的值以及通道是否关闭的指示。

长度和容量
内置的函数len和cap各种类型的参数,并返回类型的结果int。实施保证结果总是适合int。

调用参数类型结果

len(s)字符串类型字符串长度(以字节为单位)

      [n] T,* [n] T数组长度(== n)
      [] T片长度
      地图[K] T地图长度(已定义键数)
      chan T在通道缓冲区中排队的元素数

cap(s)[n] T,* [n] T数组长度(== n)

      [] T切片容量
      chan T通道缓冲容量

片的容量是在底层数组中分配空间的元素数。在任何时候,以下关系成立:

0 <= len(s)<= cap(s)
nil切片,图或通道 的长度为0. nil切片或通道的容量为0。

表达len(s)是常数,如果 s是字符串常量。表达式len(s)和 cap(s)常量,如果类型s是数组或指向数组的指针,并且表达式s不包含 通道接收或(非常量) 函数调用 ; 在这种情况下s不进行评估。否则,调用len并且cap不是常量并被s评估。

const(
c1 = imag(2i)// imag(2i)= 2.0是常数
c2 = len([10] float64 {2})// [10] float64 {2}不包含函数调用
c3 = len([10] float64 {c1})// [10] float64 {c1}不包含函数调用
c4 = len([10] float64 {imag(2i)})// imag(2i)是一个常量,不发出函数调用
c5 = len([10] float64 {imag(z)})// invalid:imag(z)是一个(非常数)函数调用

var z complex128
分配

内置函数new采用类型T,在运行时为该类型的变量分配存储,并返回*T 指向该类型的类型的值。变量按初始值部分所述进行 初始化。

新(T)
例如

键入S struct {a int; b float64}
新闻)
为类型的变量分配存储S,初始化它(a=0,b=0.0),并返回包含*S位置的地址的类型的值。

制作切片,地图和频道
内置函数make采用一种类型T,它必须是片,地图或通道类型,可选地后跟一个特定于表达式的类型列表。它返回一个值类型T(not *T)。按照关于初始值的章节所述初始化存储器 。

呼叫类型T结果

具有长度为n和容量n的类型T的(T,n)切片
具有长度为n和容量m的T型(T,n,m)切片

make(T)T型地图
将T(T,n)的地图映射为n个元素的初始空间

(T)通道无缓冲通道
(T,n)通道缓冲通道,缓冲区大小n
size参数n,m必须是整型或非类型。一个常量大小的参数必须是非负数,并可以通过类型的值表示int。如果两个n和m提供和是不变的,则 n不得大于m。如果n为负值或大于m运行时,则会发生运行时紧急。

s:= make([] int,10,100)// slice with len(s)== 10,cap(s)== 100
s:= make([] int,1e3)// slice with len(s)== cap(s)== 1000
s:= make([] int,1 << 63)// illegal:len(s)不能由int类型表示
s:= make([] int,10,0)// illegal:len(s)> cap(s)
c:= make(chan int,10)//缓冲区大小为10的通道
m:= make(map [string] int,100)//用100个元素的初始空间映射

附加和复制切片
内置功能append并copy协助常用切片操作。对于这两个函数,结果与参数引用的内存是否重叠无关。

所述可变参数函数append 追加零个或多个值x ,以s类型的S,它必须是一个切片类型,并返回型也所得到的切片,S。的值x被传递给类型的参数...T ,其中T为元素类型的 S和相应的 参数传递规则适用。作为特殊情况,append还可以接受可分配的第一个参数,[]byte其中带有第二个参数的字符串类型...。此表单附加字符串的字节。

附加(s S,x ... T)S // T是S的元素类型
如果容量s不够大以适应附加值,则append分配一个新的,足够大的底层数组,适合现有的切片元素和附加值。否则,append重新使用底层数组。

s0:= [] int {0,0}
s1:= append(s0,2)//附加单个元素s1 == [] int {0,0,2}
s2:= append(s1,3,5,7)//附加多个元素s2 == [] int {0,0,2,3,5,7}
s3:= append(s2,s0 ...)// append a slice s3 == [] int {0,0,2,3,5,7,0,0}
s4:= append(s3 [3:6],s3 [2:] ...)// append overlap slice s4 == [] int {3,5,7,2,3,5,7,0,0 }

var t [] interface {}
t = append(t,42,3.1415,“foo”)// t == [] interface {} {42,3.1415,“foo”}

var b []字节
b = append(b,“bar”...)// append string contents b == [] byte {'b','a','r'}

该功能copy将切片元素从源复制src到目标dst,并返回复制的元素数。两个参数必须具有相同的元素类型T,并且必须可以 分配给类型的切片[]T。复制的元素的数目是最小 len(src)和len(dst)。作为一种特殊情况,copy还可以接受一个目标参数,该参数可分配给[]byte一个字符串类型的源参数。此表单将字节中的字节复制到字节片中。

copy(dst,src [] T)int
copy(dst [] byte,src string)int

例子:

var a = [...] int {0,1,2,3,4,5,6,7}
var s = make([] int,6)
var b = make([]byte, 5)
n1 := copy(s, a[0:]) // n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
n2 := copy(s, s[2:]) // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
n3 := copy(b, "Hello, World!") // n3 == 5, b == []byte("Hello")
Deletion of map elements
The built-in function delete removes the element with key k from a map m. The type of k must be assignable to the key type of m.

delete(m, k) // remove element m[k] from map m
If the map m is nil or the element m[k] does not exist, delete is a no-op.

Manipulating complex numbers

三个功能组合和拆卸复数。内置函数complex从浮点实部构造一个复数值, real并imag 提取复数值的实部和虚部。

complex(realPart,imaginaryPart floatT)complexT
real(complexT)floatT
imag(complexT)floatT

参数和返回值的类型对应。为complex,这两个参数必须是相同的浮点类型的和返回类型是复杂类型与相应的浮点成分: complex64为float32参数,并 complex128为float64参数。如果其中一个参数的计算结果为无类型常数,首先 转换到其他参数的类型。如果两个参数都计算为非类型常数,则它们必须是非复数,或者它们的虚部必须为零,并且函数的返回值是无类型的复常数。

为real和imag时,参数必须是复杂类型,和返回类型是相应的浮点类型:float32用于complex64参数,并 float64为一个complex128参数。如果参数计算为非类型常数,则它必须是一个数字,函数的返回值是无类型的浮点常量。

的real和imag功能一起形成的逆 complex,所以对一个值z的复杂类型的Z, z == Z(complex(real(z), imag(z)))。

如果这些函数的操作数都是常量,则返回值是一个常数。

var a = complex(2,-2)// complex128
const b = complex(1.0,-1.4)//无类型复数常数1 - 1.4i
x:= float32(math.Cos(math.Pi / 2))// float32
var c64 = complex(5,-x)// complex64
var s uint = complex(1,0)//无类型复数常数1 + 0i可以转换为uint
_ =复(1,2 << s)//非法:2假定浮点型,不能移位
var rl = real(c64)// float32
var im = imag(a)// float64
const c = imag(b)//无类型常数-1.4
_ = imag(3 << s)// illegal:3假设复杂类型,不能移位

处理恐慌
两个内置函数,panic并且recover有助于报告和处理运行时的恐慌 和程序定义的错误条件。

func panic(interface {})
func recover()interface {}

在执行函数F时,显式调用panic或运行时的紧急 程序将终止执行F。 随后执行任何延迟的F功能。接下来,运行由F's调用者运行的任何延迟函数,以及由执行goroutine中的顶级函数延迟的任何延迟函数。在这一点上,程序被终止并且报告错误条件,包括参数的值panic。该终止序列称为恐慌。

`