Go language specification reading notes

introduction

This is a reading note for reading the Go language manual. For the Go language Chinese manual, see the Go Chinese manual .
Go is a strongly typed language with garbage collection and explicit support for concurrent programming. Programs are structured in packages to provide efficient dependency management. The current implementation uses the traditional "compile-link" model to produce executable binaries.

lexical element

note

Comments are consistent with C++ and have the following two forms:

  • Line comments begin with // and end at the end of the line. A line comment is treated as a newline.
  • Block comments begin with /* and end with */. Block comments are treated as a newline when they contain multiple lines, and as a space otherwise.

Comments cannot be nested.

mark

Tokens form the vocabulary of the Go language and come in four types: identifiers, keywords, operators and delimiters, and literals.
Whitespace consists of spaces, horizontal tabs, carriage returns, and line feeds, and is ignored unless separated by it to combine into a single token. Also, a newline or EOF (end of file) triggers the insertion of a semicolon .

semicolon

Formal grammars use the semicolon ";" as a terminator for some productions. Go programs omit most semicolons using the following two rules:

  • When input is parsed into tokens, a semicolon is automatically inserted at the end of a non-empty line in the token stream if the end-of-line token of the line is one of the following tokens:
    • identifier
    • integer, float, imaginary, rune or string literal
    • Keyword break, continue, fallthrough or return
    • operator and delimiter ++, --, ), ] or }
  • To allow compound statements to occupy a single line, the semicolon before the closing ")" or "}" can be omitted

identifier

Identifiers are used to name program entities, and an identifier consists of one or more letters and numbers. The first character of an identifier must be a letter (underscores are also considered letters) :

字母        = unicode字母 | "_" .
标识符 = 字母 { 字母 | unicode数字 } 

keywords

The following are reserved keywords and cannot be used as identifiers:

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

Operators and Delimiters

The following character sequences represent operators, separators, and other special tokens:

+    &     +=    &=     &&    ==    !=    (    )
-    |     -=    |=     ||    <     <=    [    ]
*    ^     *=    ^=     <-    >     >=    {    }
/    <<    /=    <<=    ++    =     :=    ,    ;
%    >>    %=    >>=    --    !     ...   .    :
	 &^          &^=

integer literal

An integer literal consists of a sequence of digits, the default is a decimal number, and a non-decimal number is defined by a special prefix: 0 for an octal number prefix, 0x or 0X for a hexadecimal number prefix. In the hexadecimal number face, the letters af or AF represent the values ​​10 to 15.

整数字面       = 十进制数字面 | 八进制数字面 | 十六进制数字面 .
十进制数字面   = ( "1" … "9" ) { 十进制数字 } .
八进制数字面   = "0" { 八进制数字 } .
十六进制数字面 = "0" ( "x" | "X" ) 十六进制数字 { 十六进制数字 } .

floating point number

Floating-point literals are represented by decimal floating-point constants. It consists of integer part, decimal point, fractional part and exponent part. The integer and fractional parts consist of decimal digits; the exponent part consists of an e or E followed by an optionally signed decimal exponent. The integer part or fractional part can be omitted; the decimal point or exponent can also be omitted.

浮点数字面 = 十进制数 "." [ 十进制数 ] [ 指数 ] |
			 十进制指数 |
			 "." 十进制数 [ 指数 ] .
十进制数   = 十进制数字 { 十进制数字 } .
指数       = ( "e" | "E" ) [ "+" | "-" ] 十进制数 .
0.
.25
6.67428e-11
.25e+10

imaginary number literal

Imaginary literals are represented by the imaginary part of a decimal complex constant . It iconsists .

虚数字面 = (十进制数 | 浮点数字面) "i" .
5i
2.71828i
1.e+0i

rune literal

A rune literal is represented by a rune constant. A rune literal is represented by one or more characters enclosed in single quotes. Within quotes, any character can appear except single quotes and newlines. A single character within quotes usually represents that character's Unicode value itself, while multi-character sequences beginning with a backslash are encoded differently .
Backslash escaping allows arbitrary values ​​to be encoded in ASCII text. There are 4 ways to represent an integer value as a numeric constant: \xfollowed by 2 hexadecimal digits; \ufollowed by 4 hexadecimal digits; \Ufollowed by 8 hexadecimal digits; 单个\followed by 3 octal digits.
Although these representations all produce integers, their valid ranges are different. Octal escapes can only represent values ​​between 0 and 255 . Hex escapes depend on their structure. The escape characters \u and \U denote Unicode code points, so some of these values ​​are illegal, especially those greater than 0x10FFFF and half-substitute values.

符文字面       = "'" ( unicode值 | 字节值 ) "'" .
unicode值      = unicode字符 | 小Unicode值 | 大Unicode值 | 转义字符 .
字节值         = 八进制字节值 | 十六进制字节值 .
八进制字节值   = `\` 八进制数字 八进制数字 八进制数字 .
十六进制字节值 = `\` "x" 十六进制数字 十六进制数字 .
小Unicode值    = `\` "u" 十六进制数字 十六进制数字 十六进制数字 十六进制数字 .
大Unicode值    = `\` "U" 十六进制数字 十六进制数字 十六进制数字 十六进制数字
						 十六进制数字 十六进制数字 十六进制数字 十六进制数字 .
转义字符       = `\` ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | `\` | "'" | `"` ) .
'\377'
'\x07'
'\xff'
'\u12e4'
'\U00101234'
'aa'         // 非法:太多字符
'\xa'        // 非法:太少16进制数字
'\0'         // 非法:太少8进制数字
'\uDFFF'     // 非法:半代理值
'\U00110000' // 非法:无效Unicode码点

After a backslash, certain single-character escapes denote special values:

\a   U+0007 警报或铃声
\b   U+0008 退格
\f   U+000C 换页
\n   U+000A 换行
\r   U+000D 回车
\t   U+0009 横向制表
\v   U+000b 纵向制表
\\   U+005c 反斜杠
\'   U+0027 单引号(仅在符文字面中有效)
\"   U+0022 双引号(仅在字符串字面中有效)

All other sequences beginning with a backslash are illegal.

string literal

String literals represent string constants, available by concatenating sequences of characters. It has two forms: raw string literals and interpreted string literals .
A raw string literal is the sequence of characters between backticks ``, within which any character except backticks is legal. Backslashes have no special meaning and strings can contain newlines. Carriage returns in raw string literals are discarded from the raw string value.
Interprets a string literal as a sequence of characters between double quotes "". Inside the quotes, backslash escape sequences are interpreted with the same restrictions as in rune literals.

字符串字面     = 原始字符串字面 | 解译字符串字面 .
原始字符串字面 = "`" { unicode字符 | 换行符 } "`" .
解译字符串字面 = `"` { unicode值 | 字节值 } `"` .
`abc`  // 等价于 "abc"
`\n
\n`    // 等价于 "\\n\n\\n"
"Hello, world!\n"
"\uD800"       // 非法:半代理值
"\U00110000"   // 非法:无效的Unicode码点

The following strings all mean the same thing:

"日本語"                                // UTF-8输入的文本
`日本語`                                // UTF-8输入的原始字面文本
"\u65e5\u672c\u8a9e"                    // 显式的Unicode码点
"\U000065e5\U0000672c\U00008a9e"        // 显式的Unicode码点
"\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"  // 显式的UTF-8字节

constant

Constants include Boolean constants, character constants, integer constants, floating point constants, complex constants, and string constants. Character, integer, floating-point, and complex constants are collectively referred to as numeric constants.
Although numeric constants can have arbitrary precision in the language, compilers may implement them using their finite-precision internal representation. That is, each implementation must:

  • Use at least 256 bits to represent integer constants
  • Use at least 256 bits to represent floating-point constants, including complex constants and mantissas; use at least 32 bits to represent exponent symbols.
  • An error is given if an integer constant cannot be represented exactly.
  • An error is given if a floating-point or complex constant cannot be represented due to overflow.
  • If a floating-point or complex constant cannot be represented due to precision limitations, it is rounded to the nearest representable constant .

type

A type can be specified by a type name or a type literal, which will compose a new type from previously declared types.
The names of instances of Boolean, numeric and string types are pre-declared. Composite types such as arrays, structures, pointers, functions, interfaces, slices, maps, and channels can be constructed from type literals.
A variable's static type (or type) is the type defined by its declaration. Variables of interface type also have a unique dynamic type, which is the actual type of the value stored in the variable at runtime. The dynamic type may vary during execution, but for the static type of an interface variable, it is always assignable. For non-interface types, their dynamic type is always their static type. (Like c++ runtime polymorphism?)
Each type T has a basic type: if T is a pre-declared type or a type literal, its corresponding basic type is T itself. Otherwise, the base type of T is the base type of the underlying type in its type declaration.

type T1 string
type T2 T1	/
type T3 []T1
type T4 T3

The basic type of T1 and T2 is string. The basic type of T3 and T4 is []T1.

method set

A type can have a method set associated with it (§Interface Type, §Method Declaration). The method set of an interface type is its interface. The method set of any other type T consists of all methods with receiver type T. The method set corresponding to a pointer type *T is the set of all methods with receiver *T or T (that is, it also contains the method set of T). Any other type has an empty method set. In a method set, each method must have a unique method name. A type's method set determines the interfaces it implements and the methods that can be invoked using the type's receivers.

Boolean type

The Boolean type represents the set of Boolean values ​​represented by the predeclared constants true and false. The predeclared boolean type is bool.

value type

Numeric types represent sets of integer and floating-point values. The schema-neutral pre-declared numeric types are:

uint8       所有无符号 8位整数集(0 到 255)
uint16      所有无符号16位整数集(0 到 65535)
uint32      所有无符号32位整数集(0 到 4294967295)
uint64      所有无符号64位整数集(0 到 18446744073709551615)

int8        所有带符号 8位整数集(-128 到 127)
int16       所有带符号16位整数集(-32768 到 32767)
int32       所有带符号32位整数集(-2147483648 到 2147483647)
int64       所有带符号64位整数集(-9223372036854775808 到 9223372036854775807)

float32     所有IEEE-754 32位浮点数集
float64     所有IEEE-754 64位浮点数集

complex64   所有带float32实部和虚部的复数集
complex128  所有带float64实部和虚部的复数集

byte        uint8的别名
rune        int32的别名

Type conversions are necessary when different numeric types are mixed in an expression or assignment.

string type

Strings are immutable: once created, the contents of a string cannot be changed. The pre-declared string type is string.
The length of the string s can be obtained using a built-in function len. If the string is constant, its length is a compile-time constant. The bytes of the string are accessible by integers 0 to len(s)-1. It is illegal to take the address of such an element; &s[i] is invalid if s[i] is the ith byte of the string.

array type

An array is a numbered sequence of elements of a single type, called the element type.

数组类型 = "[" 数组长度 "]" 元素类型 .
数组长度 = 表达式 .
元素类型 = 类型 .

The length is part of the array type and must evaluate to a representable non-negative constant of type int. The length of the array a can be obtained using the built-in function len, and its elements can be addressed by integer subscripts 0 to len(a)-1. Array types are always one-dimensional, but can be combined to form multidimensional types.

[32]byte
[2*N] struct { x, y int32 }
[1000]*float64	//float64指针构成的数组
[3][5]int //二维数组,3为第一维长度,5为第二维长度
[2][2][2]float64  // 多维数组

slice type

A slice is a reference to a contiguous segment of an array and a sequence of numbers containing the elements of this array. A slice type represents the set of all slices whose elements are of type array. The value of an uninitialized slice is nil. Slice (slice) is the most important type in go and must be mastered proficiently.

切片类型 = "[" "]" 元素类型 .

Like arrays, slices are indexable and have a length. The length of a slice s can be obtained through a built-in function len; unlike an array, a slice can be changed during execution, and its elements can be addressed by integers 0 to len(s)-1. The slice subscript for a given element may be smaller than its subscript in its underlying array.
Once a slice is initialized, it is always accompanied by a primitive array containing its elements. Thus, a slice shares storage with its array and other slices of this array; in contrast, different arrays always represent their different storage.
A sliced ​​primitive array extends the end of its slice. The capacity is a measure of this expansion: it is the sum of the length of the slice and the length of the array following the slice; a slice whose length reaches its capacity can be created by 'cutting' a new one from the original slice. The capacity of slice a can cap(a)be obtained .
A new, initialized slice value of a given element type T makeis created using the built-in function, which takes a slice type and parameters specifying its length and optional capacity:

make([]T, length)
make([]T, length, capacity)

Generating a slice directly is the same as allocating the array and then slicing it, so these two examples result in the same slice:

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

structure type

A structure is a named sequence of elements, where each element has a name and a type. Field names can be specified explicitly (list of identifiers) or implicitly (anonymous fields). Within a structure, non-blank field names must be unique .

结构类型 = "struct" "{" { 字段声明 ";" } "}" .
字段声明 = (标识符列表 类型 | 匿名字段) [ 标注 ] .
匿名字段 = [ "*" ] 类型名 .
标注     = 字符串字面 .
// 空结构.
struct {}

// 带6个字段的结构
struct {
	x, y int
	u float32
	_ float32  // 填充
	A *[]int
	F func()
}

A field declared by having a type without an explicit field name is an anonymous field , also known as an embedded field or an embedding of this type within the structure. This field type * must be implemented as a type name T or a pointer T to a non-interface type name , and T itself cannot be a pointer type . Unqualified type names behave like field names.

// 带类型为T1,*T2,P.T3和*P.T4的4个匿名字段的结构
struct {
	T1        // 字段名为T1
	*T2       // 字段名为T2
	P.T3      // 字段名为T3
	*P.T4     // 字段名为T4
	x, y int  // 字段名为x和y
}

The following are illegal declarations because field names must be unique within a struct type:

struct {
	T     // 与匿名字段*T及*P.T相冲突
	*T    // 与匿名字段T及*P.T相冲突
	*P.T  // 与匿名字段T及*T相冲突
}

See below for a practical usage example:

package main
import "fmt"

type Person struct{
	name string
	sex string
	age int32
}

type Student struct{
	Person
	id int32
}

func main() {
	s1 := Student{Person{"zwf", "man", 20}, 10047813}
	fmt.Println(s1)
}

The output is as follows:
insert image description here

pointer type

A pointer type represents a set of all pointers to variables of a given type, called the underlying type of the pointer. The value of an uninitialized pointer is nil.

指针类型 = "*" 基础类型 .
基础类型 = 类型 .
*Point
*[4]int

function type

A function type represents all sets with the same parameter and return type . The value of an uninitialized function type variable is nil.

函数类型 = "func" 签名 .
签名     = 形参 [ 结果 ] .
结果     = 形参 | 类型 .
形参     = "(" [ 形参列表 [ "," ] ] ")" .
形参列表 = 形参声明 { "," 形参声明 } .
形参声明 = [ 标识符列表 ] [ "..." ] 类型 .

Functions can specify multiple return values.
The last parameter in a function signature may have a type ...prefixed . A function with such parameters is called a variadic function, which takes zero or more arguments.
In the list of formal parameters or results, its name (list of identifiers) must both be present or neither. If present, each name represents an item of the specified type (parameter or result), and all non-blank names in the signature must be unique. If absent, each type represents an item of that type. If there happens to be an unnamed value, it may be written as an unparenthesized type, except that the list of formal parameters and results is always in parentheses:

type FuncA func(int, int, int) (bool, bool)	//正确,此函数类型有两个返回值
type FuncB func(i int, int, int) (bool, bool)	//错误,形参列表混用有命名和无命名的选项
type FuncC func(int, int, int) (b bool, bool)	//错误,返回值列表混用有命名和无命名的选项
func(prefix string, values ...int)//可变参数列表

Interface Type

An interface type specifies a set of methods called an interface. A variable of interface type can store a value of any type with a method set that is a superset of this interface. This type represents an implementation of this interface. The value of an uninitialized interface type variable is nil.

接口类型   = "interface" "{" { 方法实现 ";" } "}" .
方法实现   = 方法名 签名 | 接口类型名 .
方法名     = 标识符 .
接口类型名 = 类型名 .

In an interface type, each method must have a unique name

// 一个简单的File接口
interface {
	Read(b Buffer) bool
	Write(b Buffer) bool
	Close()
}

An interface can replace the implementation of a method by including an interface type named T. This is called embedding the interface, and it is equivalent to explicitly enumerating the methods in T in the interface.

type Man interface{
	run()
	walk()
}

type SuperMan interface{
	Man	//等于枚举了Man中的方法
	fly()
}

An interface type cannot nest itself directly or indirectly.

mapping type

A map is an unordered group of elements of the same type, which is called an element type; a map is indexed by a unique key set of another type, which is called a key type. An uninitialized map value is nil.

映射类型    = "map" "[" 键类型 "]" 元素类型 .
键类型      = 类型 .

The comparison operators == and != must be fully defined by operands of the key type; thus the key type cannot be a function, map, or slice. If the key type is an interface type, these comparison operators must be defined by dynamic key values; failure will result in a runtime panic (i.e. exception).
The number of elements is called the length. For a map m, its length can lenbe obtained and can be changed at execution time. Elements can be added at execution time using assignment and retrieved via subscript expressions; they can also deletebe removed .
A new, empty map value is created using the built-in function make, which takes the map type and optional capacity as argument hints:

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

The initial capacity does not limit the size of the map, because the map grows to accommodate the number of items stored in it.

channel type

Channels provide a mechanism for two concurrently executing functions to execute synchronously and communicate by passing values ​​of concrete element types. Uninitialized channel values ​​are nil.

信道类型 = ( "chan" [ "<-" ] | "<-" "chan" ) 元素类型 .

<-The operator specifies the direction of the channel, send or receive. If no direction is given, the channel is bidirectional. Channels can be forced to be send-only or receive-only by type casting or assignment.

chan T          // 可以被用来发送和接收类型T的值
chan<- float64  // 只能被用来发送浮点数
<-chan int      // 只能被用来接收整数

A new, initialized channel value can be created using the built-in function make, which takes a channel type and an optional capacity as arguments:

make(chan int, 100)

Capacity sets the size of the buffer in the channel in terms of the number of elements. If the capacity is greater than zero, the channel is asynchronous: If the buffer is not full (send) or not empty (receive), the communication operation succeeds without blocking, and elements are received in the send sequence. If the capacity is zero or none, communication will only succeed if both the sender and receiver are ready. nil The channel is never ready for communication.
Channels can be closeclosed via built-in functions; the multivalued form of the receive operator tests whether the channel is closed.

Properties of Types and Values

Type ID

A named type is always different from an unnamed type. Two unnamed types have the same type if their corresponding types are literally the same. The determination of the same type follows the following rules:

  • Two array types are of the same type if their elements are of the same type and have the same length.
  • Two slice types are of the same type if their element types are the same.
  • If two structure types have the same field sequence, the same corresponding field name, the same type, and the same label, then their types are the same. Two anonymous fields are considered to have the same name. Lowercase field names from different packages are always different.
  • Two pointer types are of the same type if their underlying types are the same.
  • If two function types have the same number of formal parameters, the same return value, the same corresponding formal parameter types, the same return value type, and both functions are variable or non-variable, then their types are the same. Parameter and return value names do not need to match.
  • If two interface types have the same method set, the same name, and the same function type, then their types are the same. Lowercase method names from different packages are always different. Whether the two interface types are the same has nothing to do with the order of the methods.
  • Two map types have the same type if their key-value types are the same.
  • If two channel types have the same value type and the same direction, then they have the same type.

Given the following declaration:

type (
	T0 []string
	T1 []string
	T2 struct{ a, b int }
	T3 struct{ a, c int }
	T4 func(int, float64) *T0
	T5 func(x int, y float64) *[]string
)

T0 and T1 are different because they have different declared type names; func(int, float64) *T0 and func(x int, y float64) *[]string are different because T0 is different from []string.

Assignability

The value x can be assigned to a variable of type T in the following cases:

  • when x is of the same type as T.
  • when x's types V and T have the same base type and at least one of V or T is not a named type.
  • When T is an interface type and x implements T.
  • When x is a bidirectional channel value, T is a channel type, the type V of x and the element type of T are the same and at least one of V or T is not a named type.
  • when x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
  • When x is an untyped constant representable by a value of type T.

Any type can be assigned a blank identifier _.

piece

Blocks are declarations and statements enclosed in curly braces. In addition to explicit source blocks, there are also implicit blocks:

  • The global block contains all Go source text.
  • Each package has package blocks that contain all of its Go source text.
  • Each file has a file block that contains all of its Go source text.
  • Each if, for, and switch statement is considered to be in its own implicit block.
  • The clauses in each switch or select statement behave like implicit blocks.

Blocks can be nested and affect scope.

Declaration and scope

In a program, every identifier must be declared. The same identifier cannot be declared twice in the same block, and it cannot be declared in the file and package block at the same time.
Go uses blocks to represent lexical scope:

  1. The scope of predeclared identifiers is the global block.
  2. Identifiers declared at the top level (that is, outside any functions) representing constants, types, variables, or functions (rather than methods) have the scope of the package block.
  3. The package name of an imported package is scoped to the file block containing the import declaration.
  4. An identifier representing a method receiver, function parameter, or return value variable, scoped to the body of the function.
  5. The scope of an identifier declared as a constant or variable in a function begins at the end of the specific constant implementation or variable implementation (ShortVarDecl means short variable declaration) in the function and ends at the end of the innermost containing block.
  6. The scope of an identifier declared as a type in a function starts at the identifier of the concrete type implementation in that function and ends at the end of the innermost containing block.

An identifier declared within a block can be redeclared within its inner block.
A package clause (for example package main) is not a declaration, and the package name does not appear in any scope. Its purpose is to identify whether the file belongs to the same package and to specify the default package name for import declarations.

label scope

Labels are declared with label statements and used in break, continue and goto statements:

Error: log.Panic("error encountered")	//设定标签Error

It is illegal to define tags that will not be used.
In contrast to other identifiers, tags are not scoped and do not conflict with non-labeled identifiers. The scope of a label is the body of the function it is declared in, excluding any nested functions.

blank identifier

_Denoted by the underscore character , it can be used in declarations like any other identifier, but the identifier cannot be passed into a new binding.

predeclared identifier

Within a global block, the following identifiers are implicitly declared:

类型:
	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

exportable identifier

Identifiers can be exported to allow access from another package. An identifier that meets the following conditions is an exportable identifier:

  1. The first character of the identifier name is a Unicode uppercase letter (Unicode category "Lu")
  2. The identifier has been declared in a package block or is a field or method name.

uniqueness of the identifier

Two identifiers are different if they are spelled differently, or if they appear in different packages and are not exported. Otherwise, they are the same.

constant declaration

A constant declaration binds a list of identifiers (that is, constant names) to the values ​​of a list of constant expressions. There must be as many identifiers as there are expressions, and the nth identifier on the left is bound to the value of the nth expression on the right.
If a type is specified, all constants will get that type implementation, and the expression must be assignable for that type. If type is omitted, the constant gets the concrete type of its corresponding expression. If the expression evaluates to an untyped constant, the remaining declared untyped constants and the constant identifier represent their constant values.

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

In the declaration list enclosed in parentheses after const, any expression list can be omitted except the first sentence declaration. If the first preceding non-null expression has a type, then such an empty list is equivalent to a substitution of the literal and type of that expression. Thus, omitting a list of expressions is equivalent to repeating the previous list. Its number of identifiers must be equal to the number of the previous expression:

const (
	i1 int64 = 1
	i2	//i2为1
	f11, f12 float32 = 1.1, 1.2
	f21, f22	//f21为1.1, f21为1.2
)

iota

Predeclaring the identifier iota in a constant declaration represents a contiguous untyped integer constant. It is reset to 0 whenever the reserved word const appears in the source code and after each constant implementation increment. It can be used to construct sets of related constants:

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

const (
	a = 1 << iota // a == 1 (iota已重置)
	b = 1 << iota // b == 2
	c = 1 << iota // c == 4
)

In the expression list, the value of each iota is the same, because it is only incremented after each constant realization:

const (
	bit0, mask0 = 1 << iota, 1<<iota - 1  // bit0 == 1, mask0 == 0, 注意mask0并不是1
	bit1, mask1                           // bit1 == 2, mask1 == 1
	_, _                                  // 跳过 iota == 2
	bit3, mask3                           // bit3 == 8, mask3 == 7
)

type declaration

A type declaration binds an identifier, type name, to a new type that has the same base type as an existing type. New types differ from existing types.

type IntArray [16]int
type (
	Point struct{ x, y float64 }
	Polar Point
)

The declared type does not inherit any method bindings to existing types, but the method set of interface types or elements of composite types remains unchanged:

// 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 declarations can be used to define different boolean, number or string types and attach methods to them:

// 类型声明重定义int类型
type TimeZone int
// 为其附加String接口
func (tz TimeZone) String() string {
	return fmt.Sprintf("GMT + %dh", tz)
}
//调用
func main() {
	var tz TimeZone = 10
	fmt.Println(tz.String())
}

variable declaration

A variable declaration binds an identifier to a created variable and gives it a type and an optional initial value. The declaration uses varthe keyword .
If a list of expressions is given, variables are initialized by assigning the expressions to the variable in order; all expressions must be exhausted and all variables initialized according to them. Otherwise, each variable is initialized to a zero value.
If the type already exists, each variable is assigned that type. Otherwise, the type is evaluated according to the expression list.
If the type does not exist and its corresponding expression evaluates to an untyped constant, the type of the declared variable is described by its assignment.
If you declare a variable that will not be used in the function body, the compiler may judge it as illegal.

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”有关

short variable declaration

A short variable declaration is an abbreviation for a regular variable declaration with an initializer that is untyped, using the following syntax:

短变量声明 = 标识符列表 ":=" 表达式列表 

Equivalent to

"var" 标识符列表 = 表达式列表 .

Short variable declarations can only appear inside functions

func main() {
	i, j := 0, 10
	f := func() int { return 7 }
	fmt.Println(i, j, f())
}

Unlike regular variable declarations, short variable declarations can redeclare previously declared variables of the same type in the same block, provided there is at least one non-blank variable . Therefore, redeclarations can only appear in multivariable short declarations. A redeclaration cannot create new variables; it can only assign new values ​​to the original variables:

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

function declaration

A function declaration binds an identifier, the function name, to the function.

函数声明 = "func" 函数名(形参列表)(返回值列表) [ 函数体 ] .
func swap(x, y int) (int, int) {
	return y, x
}

A function declaration can omit the function body. Such an identifier provides a signature for a function implemented outside of Go:

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

method declaration

Methods are functions with receivers. A method declaration binds an identifier, the method name, to a method. It also associates the receiver's underlying type with the method:

方法声明   = "func" 接收者 方法名 签名 [ 函数体 ] .
接收者     = "(" [ 标识符 ] [ "*" ] 基础类型名 ")" .
基础类型名 = 标识符 .

The receiver type must be of the form T or *T, where T is the type name. The type represented by T is called the underlying type of the receiver, it cannot be a pointer or interface type and must be declared as a method in the same package. That is, the method is bound to the underlying type and the method name is only visible to selectors of this type inside it:

//Vector 向量
type Vector struct{ x, y float64 }

//Length 获取向量的长度
func (p *Vector) Length() float64 {
	return math.Sqrt(p.x*p.x + p.y*p.y)
}

//Scale 使向量按比例伸缩
func (p *Vector) Scale(factor float64) *Vector {
	return &Vector{p.x * factor, p.y * factor}
}

func main() {
	v := Vector{1, 1}
	fmt.Println(v.Length(), v.Scale(2).Length())
}

The output is as follows:
insert image description here

The type of the method is the type of the function that takes the receiver as its first argument. For example, the method Scale in the example above has type

func(p *Point, factor float64)

However, functions declared this way are not methods.

expression

qualified identifier

A qualified identifier .is an identifier qualified with a package name prefix. Neither the package name nor the identifier can be blank. Qualified identifiers are used to access identifiers in another package, which must be imported. Identifiers must be exported and declared in the package's package block:

math.Sin

compound literal

Compound literals are evaluated every time a value is constructed for a struct, array, slice, map, or a new value is created. They consist of the type of the value followed by a list enclosed in curly braces. An element can be a single expression or a key-value pair.
The literal type must be a structure, array, slice, or map type (syntax rules enforce this constraint unless the type is given as a type name). The type of the expression must be assignable to its respective fields, elements, and key types of the literal type, that is, without additional conversions. As the field names of structure literals, the subscripts of arrays and slices, and the keys of map literals, the keys are decipherable. For map literals, all elements must have keys. Specifying more than one element with the same field name or constant key value will generate an error.
The following rules apply to structure literals:

  • Keys must be field names declared in literal types
  • A list of elements that does not contain any keys must list the elements of each structure field in the order in which the fields are declared.
  • If any of the elements have a key, then every element must have a key.
  • A list of elements containing keys need not have elements for every structure field. Ignored fields get a zero value
  • A literal may omit a list of elements; such a literal evaluates to the zero value for its type.
  • Specifying an element for an unexported field of a structure belonging to a different package generates an error.

Given a type declaration:

//Point32 表示一个点
type Point32 struct{ x, y, z float64 }

//Line 表示线
type Line struct{ p, q Point32 }

Its variables are declared as follows:

origin := Point3D{}                            // Point3D 为零值
line := Line{origin, Point3D{y: -4, z: 12.3}}  // line.q.x 为零值,

Note that the list is a key-value pair, which must be used :but cannot be used =. Pointers to unique instances of compound literals
can be generated using address-of characters :&

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

The length of an array literal is the length specified by the literal type. If there are fewer elements than the length provided literally, missing elements are set to the zero value of the array's element type. Supplying an element with a subscript value outside the range of the array subscript produces an error.
Notation ...Specify an array whose length is equal to the index of the largest element plus one:

buffer := [10]string{}             // len(buffer) == 10,默认为空字符串
intSet := [6]int{1, 2, 3, 5}       // len(intSet) == 6,最后两个数字为0
days := [...]string{"Sat", "Sun"}  // len(days) == 2

Slice literals describe all primitive array literals. Therefore, the length and capacity of a slice literal is the subscript of its largest element plus one. Here is a shortcut for slicing operations applied to arrays:

tmp : [n]T{x1, x2, ... xn}
tmp[0:n]

Example:

tmp := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
var t = tmp[5:9]
for k, v := range t {
	fmt.Println(k, v)
}

In a compound literal of array, slice, or map type T, the respective element types may be omitted if the elements are themselves compound literals and the compound literal has the same element type as T. Similarly, when the element type is *T, if its element is the address of a compound literal, &T can be omitted:

	points := [...]Point{
   
   {1.0, 1.0}, {2.0, 2.0}}	//元素省略Point
	pointersOfPoints := [...]*Point{
   
   {1.5, -3.5}, {0, 0}}	//元素省略了&Point

A resolution ambiguity arises when a compound literal uses the typename form of a literal type and it occurs between the keyword "if", "for" or "switch" statement and its opening brace. Because in this literal, the curly braces around the expression will be confused with those before the statement block. To resolve the ambiguity in this rare case, the compound literal must appear within parentheses:

if x == (T{a,b,c}[i]) { … }	//错误用法
if (x == T{a,b,c}[i]) { … }	//正确用法

function literal

A function literal represents an anonymous function. It consists of the specification of the function type and function body. Function literals can be assigned to a variable or called directly:

//函数赋值给变量
f := func(x, y int) int { return x + y }
fmt.Println(f(3, 4))
//函数直接调用
fmt.Println(func(x, y int) int { return x + y }(3, 4))

selector

View the following form:

x.f

A field or method f representing the value x (sometimes *x, see below). The identifier f is called the (field or method) selector and it cannot be a blank identifier. The type of the selector expression is the type of f.
The selector f may represent a field or method f of type T, or a field or method f that refers to a nested anonymous field in T. The amount obtained by traversing the anonymous fields of region f in T is called its depth . A field or method f declared with T has depth 0. The depth of a field or method f declared in T with an anonymous field A is the depth of f in A plus one.
The following rules apply to selectors:

  • For a value x of non-interface type T or *T, the f in xf denotes the field or method at the shallowest depth in T. If there is more than one f, the selector expression is illegal.
  • For a variable x of interface type I, xf denotes the real method named f that assigns the value of x. If there is no method named f in I's method set, the selector is invalid.
  • In all other cases, all xf are illegal.
  • Assigning, evaluating, or calling xf will generate a runtime panic if x is of pointer or interface type and the value is nil.

The selector automatically dereferences the pointer to the structure. If x is a pointer to a structure, x.yit is an abbreviation (*x).yof ; if the field y is also a pointer to a structure, x.y.zit is an abbreviation (*(*x).y).zof , and so on. Shorthand for if x contains an anonymous field of type *A, and A is also a structure x.ftype (*x.A).f. (Pay special attention to the last case.)
Check out the following examples:

package main

import "fmt"

type T0 struct {
	x int
}

func (recv *T0) M0() {
	fmt.Println("T0.M0")
}

type T1 struct {
	y int
}

func (recv *T1) M1() {
	fmt.Println("T1.M1")
}

type T2 struct {
	z int
	T1
	*T0
}

func (recv *T2) M1() {
	fmt.Println("T2.M1")
}

func (recv *T2) M2() {
	fmt.Println("T2.M2")
}

func main() {
	var p *T2 = new(T2)
	p.T0 = new(T0)
	p.M0()
	p.M1()
	p.M2()
	fmt.Println(p.x, p.y, p.z)
}

outputinsert image description here

method expression

If M is in the method set of type T, TM is a callable function,
see the following structure:

type T struct {
	a int
}
func (tv  T) Mv(a int) int         { return 0 }  // value receiver
func (tp *T) Mp(f float32) float32 { return 1 }  // pointer receiver

Then the following calls are equivalent:

var (
	v T
	p = &v
)

//以下两种调用等价
v.Mv(0)
T.Mv(v, 0)

//以下3种调用等价
p.Mp(0)
(*p).Mp(0)
(*T).Mp(p, 0)

subscript expression

A primary expression of the form a[x]means that the elements of the array, slice, string, or map a are retrieved by x. The value x is called a subscript or map key.
If a is not a map:

  • The subscript x must be an integer value; if 0 <= x < len(a), the subscript is within the bounds, otherwise it is out of bounds
  • a The constant subscript must be a value that can be expressed as an int type

For a of array type A or *A:

  • Constant subscripts must be in bounds
  • Raises a runtime panic if a is nil or x is out of bounds at runtime
  • a[x] is an array element whose subscript is x, and the type of a[x] is the element type of A

For a of slice type S:

  • If the slice is nil, or x is out of bounds at runtime, a runtime panic is raised
  • a[x] is a slice element with subscript x and the type of a[x] is the element type of S

For a of type string type T:

  • If the string a is also a constant, the constant subscript must be within bounds.
  • If x is out of range, a runtime panic occurs
  • a[x] is the byte with subscript x and the type of a[x] is byte
  • a[x] is not assignable

For a of type mapped type M:

  • The type of x must be assignable to the key type of M
  • If the map contains an item with key x, then a[x] is the map value for key x, and the type of a[x] is the value type of M
  • If the map is nil or contains no such items, a[x] is the zero value of the M value type

In a map a of type map[K]V, subscript expressions can use a special form:

v, ok := a[x]

Assignment or initialization, the subscript expression result is a value pair of type (V, bool). In this form, ok evaluates to true if the key x is already in the map, and false otherwise. The value of v is the single-valued form of a[x]. Assigning a value to an element of a nil map causes a runtime panic

slice

For a string, array, pointer to array, or slice a, a[low : high]a string or slice is constructed.
The subscript of a slice starts at 0 and has a length equal to high - low. For convenience, any subscript can be omitted. An omitted low subscript defaults to zero; an omitted high subscript defaults to the length of the cut operand:

	a := [5]int{1, 2, 3, 4, 5}
	s1 := a[1:4]
	s2 := a[:4] //等价于a[0:4]
	s3 := a[1:] //等价于a[1:5]

For slices, the upper bound is the slice's capacity cap(a) rather than its length. The constant subscript must be a non-negative value and can be represented as a value of type int. If their subscripts are also constants, they must satisfy low <= high. If a is nil or its subscript is out of bounds at runtime, a runtime panic is raised.

type assertion

The notation x.(T)is called a type assertion. Asserts that x is not nil and that the value stored in x is of type T.
More precisely, x.(T) asserts that the dynamic type of x is the same as T if T is a non-interface type. In this case, T must implement the (interface) type of x, unless its type assertion is invalid because it cannot store a value of type T for x. If T is an interface type, x.(T) asserts that the dynamic type of x implements interface T.
If the type assertion holds, the value of the expression is the value stored in x and its type is T. If the type assertion fails, a runtime panic occurs:

var x interface{} = 7  // x 拥有动态类型 int 与值 7
i := x.(int)           // i 拥有类型 int 与值 7

type I interface { m() }
var y I
s := y.(string)        // 非法:string 没有实现 I(缺少方法 m)
r := y.(io.Reader)     // r 拥有 类型 io.Reader 且 y 必须同时实现了 I 和 io.Reader,特别注意这种情况!

If the type assertion starts with

v, ok := x.(T)

The form of is used for assignment or initialization, and the result of the assertion is a value pair of type (T, bool). If the assertion is true, the expression returns the pair (x.(T), true); otherwise, the expression returns (Z, false), where Z is the zero value of type T. This situation does not generate a runtime panic. A type assertion in this construct behaves like a function call returning a value and a boolean to indicate success.

transfer

In a function call, function values ​​and arguments are evaluated in the usual order (that is, from left to right).

pass arguments to formal parameters

If f is a variadic function with parameter ...Ttype , then in this function, the actual parameter is equivalent to the formal parameter of type []T. For each invocation of f, the argument passed to the last formal parameter is a new slice of type []T, whose successive elements are the actual arguments, which must all be assignable to type T. Thus, the length of the slice is the number of arguments bound to the last parameter, and may be different for each call site.

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

If the last argument is assignable to a slice of type []T followed by ..., it may be passed as the value of the ...T parameter unchanged:

s := []string{"James", "Jasmine"}
Greeting("goodbye:", s...)	//who 将作为与 s 一样的值拥有与其相同的基本数组

operator

二元操作符 = "||" | "&&" | 关系操作符 | 加法操作符 | 乘法操作符 .
关系操作符 = "==" | "!=" | "<" | "<=" | ">" | ">=" .
加法操作符 = "+" | "-" | "|" | "^" .
乘法操作符 = "*" | "/" | "%" | "<<" | ">>" | "&" | "&^" .

一元操作符 = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .

The four basic arithmetic operators (+, -, *, /) apply to integer, floating-point, and complex types; + +=also apply to strings.
x / y are truncated towards zero. If the dividend is constant, it must not be zero. If the dividend is zero at runtime, a runtime panic occurs.
For integer operands, the unary operators +, -, and ^ are defined as follows:

+x                  即为 0 + x
-x    相反数        即为 0 - x
^x    按位补码      即为 m ^ x  对于无符号的 x,m = 所有位置为1;对于带符号的 x,m = -1

operator precedence

The overall order is

一元操作符 > 算术操作符 > 比较操作符 > 逻辑操作符
优先级        操作符
	6             +  -  ! ^ * & <-
	5             *  /  %  <<  >>  &  &^
	4             +  -  |  ^
	3             ==  !=  <  <=  >  >=
	2             &&
	1             ||

Binary operators of the same precedence associate from left to right.
In particular, it should be noted that in the go language, the ++ and – operators are statements, not expressions, and they do not belong to the operator level. Therefore, the statement *p++ is equivalent to (*p)++.

arithmetic operator

The four basic arithmetic operators (+, -, *, /) apply to integer, floating-point, and complex types; + also applies to strings. All other arithmetic operators apply only to integers.

+    和              integers, floats, complex values, strings
-    差              integers, floats, complex values
*    积              integers, floats, complex values
/    商              integers, floats, complex values
%    余              integers

&    按位与          integers
|    按位或          integers
^    按位异或        integers
&^   位清除(与非)  integers

<<   向左移位        integer << unsigned integer
>>   向右移位        integer >> unsigned integer

For integers x, y if q=x/y, r= x%y, then they satisfy the following relationship:

r = x - x/y*y and |r| < |y|

Also x/y are truncated towards zero, so the result is:

 x     y     x / y     x % y
 5     3       1         2
-5     3      -1        -2
 5    -3      -1         2
-5    -3       1        -2

It turns out that the sign of the remainder is the same as that of x.
An unexpected rule is that if x is the largest negative number of its type, then x/-1==x:

							x	x/-1													
int8                     -128	-128												 	
int16                  -32768	-32768
int32             -2147483648	-2147483648
int64    -9223372036854775808	-9223372036854775808

If the dividend is constant, it must not be zero. If the dividend is zero at runtime, a runtime panic occurs.
Strings can be concatenated using the + operator or the += assignment operator:

在这里插入代码片

The shift operators shift the left operand by the shift count specified by the right operand. If the left operand is a signed integer, they perform an arithmetic shift (that is, the sign bit needs to be considered, usually the left side is filled with 1 when a negative number is shifted to the right); if the left operand is an unsigned integer, they perform a logical shift (that is, Regardless of the sign bit, the high and low bits are filled with 0). The shift count has no upper bound. If the left operand is shifted by n bits, it behaves as if it were shifted by 1 bit n times. As a result, x << 1 is equivalent to x*2, and x >> 1 is equivalent to x/2 but truncated toward negative infinity, no matter what integer x is :

	var (
		x int8 = 3
		y int8 = -3
	)
	x<<1 // 结果为int8(6)
	x>>1 // 结果为int8(1)
	y<<1 // 结果为int8(-6)
	y>>1 // 结果为int8(-2)```

For integer operands, the unary operators +, -, and ^ are defined as follows:

+x                  即为 0 + x
-x    相反数        即为 0 - x
^x    按位补码      即为 m ^ x  对于无符号的 x,m = "所有位置为1"

integer overflow

Unsigned integer operations discard high-order overflow
For signed integers, operations +, -, *, and << legally overflow, and the resulting value persists and is determined by the signed integer representation, operation, and its operands well defined.

comparison operator

Comparison operators compare two operands and produce a Boolean value. In any comparison, the first operand must be of a type assignable to the second operand, and vice versa. The equality operators == and != apply to comparable operands. The order operators <, <=, >, and >= apply to ordered operands. The relationships and values ​​for these comparison operations are defined as follows:

  • Boolean values ​​are comparable. Two Boolean values ​​are equal if they are both true or both false.
  • Typically, integer values ​​are comparable or orderable.
  • Floating-point values ​​are comparable or orderable, as defined by the IEEE-754 standard.
  • Complex values ​​are comparable. Two complex values ​​u and v are equal if real(u) == real(v) and imag(u) == imag(v).
  • String values ​​are comparable or orderable according to bytewise lexicalization.
  • Pointer values ​​are comparable. Two pointers are equal if they point to the same value or both are nil. Pointers to apparently zero-sized variables may or may not be equal.
  • Channel values ​​are comparable. Two channel values ​​are equal if they were created by the same make call (§Creating slices, maps and channels) or both have the nil value.
  • Interface values ​​are comparable. Two interface values ​​are equal if they have the same dynamic type and equal dynamic value, or both are nil values.
  • A value x of a non-interface type X is comparable to a value t of an interface type T when the values ​​of the non-interface type X are comparable and X implements T. if t's
  • They are equal if the dynamic type is the same as X and the dynamic value of t is equal to x.
  • Two structure values ​​are comparable if all their fields are comparable. They are equal if their corresponding non-blank fields are equal.
  • Array values ​​are comparable if the values ​​of the two array element types are comparable. They are equal if their corresponding elements are equal.

Comparing two interface values ​​of the same dynamic type will cause a runtime panic if the values ​​of the dynamic type are not comparable. This behavior applies not only to direct interface value comparisons, but also when comparing arrays of interface values ​​or structs with interface values ​​as fields.
Types such as slices, maps, functions, pointers, channels, and interface values ​​are not comparable, but they are all comparable with the predeclared identifier nil.

logical operator

Logical operators apply to Boolean values ​​and produce a result of the same type as the operands. The right operand is conditionally evaluated.

&&    条件与    p && q  即  “若 p 成立则判断 q 否则返回 false”
||    条件或    p || q  即  “若 p 成立则返回 true 否则判断 q”
!     非        !p      即  “非 p”

receive operator

For an operand ch of channel type, the value of the receive operator <-ch is the value received from channel ch. The direction of the channel must allow receive operations, and the type of the receive operation is the element type of the channel. Expression blocks preceding this value are valid. Receiving from a nil channel will block forever. Receiving from a closed channel will always succeed, immediately returning a zero value for its element type :

v1 := <-ch
v2 = <-ch
f(<-ch)
<-strobe  // 在时钟脉冲和丢弃接收值之前等待

Receive expressions with

x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch

Forms used for assignment or initialization will produce an additional result of type bool to report whether the communication was successful. The value of ok is true if the received value was issued by a successful send operation to the channel; false if the received value was a zero value resulting from the channel being closed or empty.

type conversion

order of evaluation

When evaluating an expression, assignment, or Return statement, all function calls, method calls, and communication operations are evaluated in left-to-right lexical order.

statement

label statement

A labeled statement can be the target of a goto, break or continue statement:

Error: log.Panic("error encountered")

send statement

The send statement sends a value on the channel. The channel expression must be of channel type, the direction of the channel must allow the send operation, and the type of the value being sent must be assignable to the element type of the channel.
Both channel and value expressions are evaluated before communication begins. Communication blocks until sending can proceed. Sending on an unbuffered channel can proceed if the receiver is ready. If there is room in the buffer, sending on the buffered channel can continue. Sending on a closed channel causes a runtime panic. Sending on a nil channel will block forever.

ch  <- 3

assignment

In an assignment statement, subscript expressions on the left and operands of pointer indirection (including implicit pointer indirection in selectors) and expressions on the right are evaluated in the usual order. Second, assignments are made in left-to-right order. So the following expressions can be used for value exchange:

a, b = b, a  // 交换a和b

if statement

// 简单语句将在表达式求值前执行
if x := f(); x < y {
	return x
} else if x > z {
	return z
} else {
	return y
}

switch statement

It has two forms: expression selection and type selection. In expression selection, the expressions contained in the case are compared against the value of the switch expression, and in the type selection, the types contained in the case are compared against the type of the switch expression specified.

expression selection

In expression selection, the switch expression will be evaluated, and the case expression does not need to be a constant, it is evaluated from top to bottom, from left to right; the first case expression equal to the switch expression will be Execution of the statement that raised the corresponding condition; other conditions will be skipped. If no case matches and there is a "default" case, the statement will be executed. There can be at most one default case and it can appear anywhere in a "switch" statement. A missing switch expression is equivalent to the expression true.
In a case or default clause, the last statement may be fallthrougha statement indicating that control flow should pass from the end of the clause to the first statement of the next clause. Otherwise, control flows to the end of the "switch" statement.

switch tag {
default: s3()
case 0, 1, 2, 3: s1()
case 4, 5, 6, 7: s2()
}

switch {
case x < y: f1()
case x < z: f2()
case x == 4: f3()
}

type selection

Examples are as follows:

switch i := x.(type) {
case nil:
	printString("x is nil")                // i 的类型为 x 的类型(interface{})
case int:
	printInt(i)                            // i 的类型为 int
case float64:
	printFloat64(i)                        // i 的类型为 float64
case func(int) float64:
	printFunction(i)                       // i 的类型为 func(int) float64
case bool, string:
	printString("type is bool or string")  // i 的类型为 x 的类型(interface{})
default:
	printString("don't know the type")     // i 的类型为 x 的类型(interface{})

Where is the form of type assertion x.(type)using reserved words typeinstead of actual types. At this time, the case matches the actual type T for the dynamic type of the expression x. Just like the type assertion, x must be an interface type, and each non-interface type T listed in the case must implement the type of x.
fallthroughStatement not allowed in type selection.

For statement

In its simplest form, the block specified by the "for" statement is executed repeatedly as long as the Boolean condition evaluates to true. Conditions are evaluated before each iteration. If the condition is absent, it is equivalent to true:

for a < b {
	a *= 2
}

A "for" statement with a For clause is also controlled by its condition, and in addition, it can also specify an initialization or step statement, such as an assignment, an increment or decrement statement. An initialization statement can be a short variable declaration, while a step statement cannot:

for i := 0; i < 10; i++ {
	f(i)
}

A "for" statement with a "range" clause iterates over all items of the array, slice, string, or map, and the values ​​received from the channel. For each item, it assigns the iteration value to its corresponding iteration variable, and then executes the block:

var a [10]string
m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6}
for i, s := range a {
	g(i, s)
}

Go statement

The go statement starts the execution of a function call as a separate concurrent thread of control or as a goroutine in the same address space:

go Server()
go func(ch chan<- bool) { for { sleep(10); ch <- true; }} (c)

select statement

return statement

A "return" statement in a function F terminates the execution of F and optionally provides one or more return values.

Break statement

The "break" statement terminates the execution of the innermost "for", "switch" or "select" statement.
If a label is present, it must be a closing "for", "switch" or "select" statement, and this execution terminates:

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

Continue statement

The "continue" statement starts the next iteration at the step statement of the innermost "for" loop. If a label is present, it must be a closing "for" statement, and this execution will advance.

Goto statement

The "goto" statement is used to transfer control to the statement corresponding to its label.
Executing a "goto" cannot bring any variables that are not already in scope into scope at the jump point:

	goto L  // 这样不好
	v := 3
L:	//错误, 因为跳转至标签 L 处将跳过 v 的创建

A "goto" statement outside a block cannot jump to a label within that block:

if n%2 == 1 {
	goto L1
}
for n > 0 {
	f()
	n--
L1:	//错误,因为标签 L1 在"for"语句的块中而 goto 则不在
	f()
	n--
}

Defer statement

The function called by the "defer" statement will be deferred until its enclosing function returns, whether because the enclosing function executes the return statement, reaches the end of its function body, or because its corresponding goroutine enters the panic process. Deferred functions are executed immediately in the reverse order in which they were deferred, before the enclosing function returns.

// 在外围函数返回前打印 3 2 1 0
for i := 0; i <= 3; i++ {
	defer fmt.Print(i)
}

built-in function

Bag

Go programs are constructed from packages linked together. A package is constructed from one or more source files that belong to the package along with their constant, type, variable and function declarations and are mutually accessible in all files of the same package.

Organization of source files

Each source file consists of these sections:

源文件 = 包子句 ";" { 导入声明 ";" } { 顶级声明 ";" } .

package clause

The package clause starts with each source file and defines the package to which the file belongs:

package math

A set of files forms a package implementation by sharing the same package name. Implementations may require that all source files for a package be placed in the same directory. There cannot be source files of different packages under one directory file.

import statement

The import statement is used to declare the dependency relationship between the importing package and the imported package. It is illegal for a package to import itself or to import a package that does not refer to any exportable identifiers:

import   "lib/math"

Program initialization and execution

zero value

When declaring a variable without providing an explicit initialization, the memory will be given a default initialization zero value: boolean type is false, integer type is 0, floating point type is 0.0, string type is "", while pointer, function, Interface, slice, channel, and map types are nil.

program execution

A package without import declarations is func init()initialized by assigning initial values ​​to all of its package-level variables and calling any package-level functions defined in its sources with the name and signature of . A package may also contain multiple init functions, which are executed in an indeterminate order.
The init function cannot be referenced anywhere in the program. Specifically, init can neither be called explicitly, nor can a pointer to init be assigned to a function variable.
If a package has import declarations, the imported package is initialized before the package itself is initialized. If multiple packages import package P, P will only be initialized once.
A complete program is created by linking a single, non-imported package, called the main package, with all its transitively imported packages. The main package must have the package name main and declare a function with no arguments and no return value func main() {...}.
Package initialization—variable initialization and init function calls—happens consecutively in a single goroutine, one package at a time. An init function may be started in other goroutines, which may run alongside initialization code. However, initialization always executes the init functions sequentially: it doesn't start the next one until the previous init returns.

mistake

The predeclared type error is defined as:

type error interface {
    
    
	Error() string
}

It is a traditional interface representing an error state, with a value of nil indicating no error.

runtime panic

system consideration

package unsafe

unsafe provides tools for low-level programming including operations that violate the type system. Packages using unsafe must be manually reviewed for type safety. This package provides the following interfaces:

package unsafe
type ArbitraryType int  // 任意Go类型的简写,它并非真正的类型
type Pointer *ArbitraryType
func Alignof(variable ArbitraryType) uintptr
func Offsetof(selector ArbitraryType) uintptr
func Sizeof(variable ArbitraryType) uintptr

Any pointer or value of primitive type uintptr can be converted to Pointer and vice versa.
The functions Alignof and Sizeof accept an expression x of any type and return its column count or size, respectively.
The function Offsetof takes a structure member representing a structure field of any type and returns the offset in bytes of the field relative to the address of the structure.

Size and Alignment Guarantees

For numeric types, the following sizes are guaranteed:

类型                               字节大小

byte, uint8, int8                     1
uint16, int16                         2
uint32, int32, float32                4
uint64, int64, float64, complex64     8
complex128                           16

The following minimum alignment properties are guaranteed:

  1. For any type of variable x: unsafe.Alignof(x) is at least 1.
  2. For a variable x of structure type: for each field f of x, the value of unsafe.Alignof(x) is the largest of all unsafe.Alignof(xf) values, but at least 1.
  3. For a variable x of array type: unsafe.Alignof(x) is the same as unsafe.Alignof(x[0]) but at least 1
  4. If a structure or array type contains no fields or elements with a size greater than zero, their size is zero. Two different zero-sized variables may have the same address in memory.

Guess you like

Origin blog.csdn.net/m0_37979033/article/details/109093930