Summary of basic knowledge of Go language (grammar variables numeric types expressions control structures etc.)
- 2020-05-05 11:22:27
- OfStack
1.
golang source code USES UTF-8 coding. Spaces include: white space, tab, line feed, and carriage return.
- the identifier consists of letters and Numbers (plus '_'), both of which are Unicode encoded.
- comments:
/* This is a comment; no nesting */
// So is this.
literals (literals) are similar to literals in the C language, but do not require symbols or size flags for numerical values:
23
0x0FF
e7 is similar to the string in C, but the string is encoded in Unicode/ UTF-8. Also, \xNN always has 2 Numbers; \012 is always 3; Both are bytes:
"Hello, world\n"
"\xFF" // 1 byte
"\u00FF" // 1 Unicode char, 2 bytes of UTF-8
Native string: '\n\.abc \t\' == "\\n\\.abc \\t\\"
3. Overview of
golang is basically the syntax for the class C, but with the inverted type and declaration, and the keyword at the beginning of each declaration.
var a int
var b, c *int // Pay attention to and C The different
var d []int
type S struct { a, b int }
The basic control structure is also familiar:
if a == b { return true } else { return false }
for i = 0; i < 10; i++ { ... }
Note: no parentheses, but braces are required.
four, semicolon
A semicolon is used as a statement termination symbol, but:
- if the previous symbol is the end of the statement, the lexical analyzer will automatically insert a semicolon
at the end of the line
- note: clearer and simpler than JavaScript rules
Therefore, the following program does not require a semicolon:
package main
const three = 3
var i int = three
func main() { fmt.Printf("%d\n", i) }
In practice, the Go source code USES almost no semicolons outside the for and if clauses.
5. Numerical type
The golang numeric type (numeric types) is native and built-in and is also known as
int uint
int8 uint8 = byte
int16 uint16
int32 uint32 float32 complex64
int64 uint64 float64 complex128
There is also uintptr, a size large enough to store the value of a pointer.
These are all different types; int is not the same as int32, even on a 32-bit machine.
There is no implicit casting (but don't panic).
Bool
Common Boolean type bool, values true and false (predefined constants).
The if statement and so on use Boolean expressions.
Pointer types and integers are not Boolean types.
string
The native built-in string type represents an immutable array of bytes, that is, text. The string type is delimited by length, not terminated by the end of 0.
The string literal is of type string.
As immutable as an integer. You can reassert a value, but you cannot change its value.
Just as "3" is always 3, "hello" is always "hello".
The Go language provides good support for string manipulation.
vi. Expression (Expressions)
Most are operators of the C language.
binary operator:
The priority operator remarks
5 * / %
<
<
>
>
&
&
^
&
^ is the bit cleanup operator
4 + | ^ ^ is xor (xor)
3 == !=
<
<
=
>
>
=
2
&
&
1 ||
Unary operators include: &
! * + wok ^(plus < for communication
-)
The unary operator ^ is a complement/inverse operation.
Go vs. C expression
C programmers can be pleasantly surprised:
Fewer priority levels (should be easy).
^ instead of ~
++ and wok are no longer expression operators (x++ is a statement, not an expression; *p++ is (*p)++, not * p++))
&
^ is the new operator, which is useful in constant expressions
<
<
And >
>
An unsigned shift count is required.
No surprises:
The assignment operation is as expected: += <
<
=
&
^ =
, etc
The expression overall looks similar (subscripts, function calls, etc.)
Example:
+x
23 + 3*x[i]
x <= f()
^a >> b
f() || g()
x == y + 1 && <-ch > 0
x &^ 7 // x with the low 3 bits cleared
fmt.Printf("%5.2g\n", 2*math.Sin(PI/8))
7.234/x + 2.3i
"hello, " + "world" // concatenation
// no C-like "a" "b"
numerical transformations
Converting a value from one type to another is called a transition, and its syntax is somewhat similar to that of a function call:
uint8(intVar) // Truncate to the corresponding size
int(float64Var) // Fragment truncation
float64(intVar) // to float64
Some involve string types of transformations:
string(0 x 1234) // == "\u1234"
string(sliceOfBytes) // bytes -> bytes
string(sliceOfInts) // ints -> Unicode/UTF-8
[]byte("abc") // bytes -> bytes
[]int(" Japan � ") // Unicode/UTF-8 -> ints
Slicing (slice) is related to arrays, more on that later.
The constant
Numerical constants are "ideal Numbers" : there is no size or flag, so there is no end to U, L, or UL.
077 // octal
0xFEEDBEEEEEEEEEEEEEEEEEEEEF // hexadecimal
1 << 100
Below are integers and floating point values, of which the syntax of the literal determines the type:
1.234e5 // Floating point
1e2 // Floating point
3.2i // Floating-point imaginary
100 // The integer
constant expression
Floating point and integer constants can be arbitrarily combined, and the type of the final expression is determined by the type of the constant. The operation itself also depends on the type.
2*3.14 // Floating point : 6.28
3./2 // Floating point: 1.5
3/2 // Integer: 1
3+2i // Plural: 3.0 + 2.0i
// High precision
const Ln2 = 0.69314718055994530941723212145817656807
const Log2E = 1/Ln2
The range of values is large enough (the current maximum is 1024 bits).
ideal number results in
The Go language allows constants to be used without explicit transitions, provided that the values can be represented by their type (no transition is necessary; The value is ok) :
var million int = 1e6 //float The syntax can be used here
math.Sin(1)
A constant must be represented by its class. For example, ^0 has a value of -1, not in the range 0-255.
23
0x0FF
4
viii. Declaration
The golang declaration begins with a keyword (var, const, type, func) and is in the reverse order of the declaration in C:
23
0x0FF
5
Why declare in reverse order? An early example:
23
0x0FF
6
p and q are of type *int. And the function reads better and is consistent with other declarations. There's another reason. Come on.
Var
The variable declaration begins with var.
They can have a type or an initialization expression; There should be at least one or both. The initialization expression should match the variable (and the type!). .
23
0x0FF
7
dispatches var
Typing var all the time is annoying. We can declare multiple variables as a group with parentheses:
23
0x0FF
8
This form is suitable for const,type, var, but not for func.
=:" short statement "
Within a function (only if it is within a function), the following form is declared:
23
0x0FF
9
Can be shortened to:
v := value
(this is another reason for the reverse order of name and type)
A type is the type of a value (for an ideal number, the corresponding type is int or float64 or complex128)
a, b, c, d, e := 1, 2.0, "three", FOUR, 5e0i
This form of declaration is used frequently and can also be used in loop initialization expressions such as for.
Const
Constant declarations begin with const.
They must have a constant expression that can be evaluated at compile time and, as an initialization expression, an optional type modifier.
const Pi = 22./7.
const AccuratePi float64 = 355./113
const beef, two, parsnip = "meat", 2, "veg"
const (
Monday, Tuesday, Wednesday = 1, 2, 3
Thursday, Friday, Saturday = 4, 5, 6
)
Iota
Constant declarations can use counters: iota, iota in each const block counts from 0, incrementing itself on each implicit semicolon (end of line).
const (
Monday = iota // 0
Tuesday = iota // 1
)
Shorthand: repeat the previous type and expression.
const (
loc0, bit0 uint32 = iota, 1<<iota //0 . 1
loc1, bit1 //1 . 2
loc2, bit2 //2 . 4
)
Type
The type declaration begins with type.
We'll look at more types later, but here are a few examples:
type Point struct {
x, y, z float64
name
string
}
type Operator func(a, b int) int
type SliceOfIntPointers []*int
We'll come back to functions later.
New
The built-in function new allocates memory. The syntax is similar to a function call, with type as an argument, similar to new in C++. Returns a pointer to the allocated object.
var p *Point = new(Point)
v := new(int) // v The type of *int
Later we will see how to build slices (slice)
There is no delete or free for memory release in Go. Go has a garbage collection feature.
assigns
Assignments are easy and familiar:
a = b
But Go also supports a number of assignments:
x, y, z = f1(), f2(), f3()
a, b = b, a // interaction a,b The value of the
The function supports multiple return values (more on that later) :
nbytes, error := Write(buf)
9. Control structure
Similar to C, but different in many places.
Go supports if, for, and switch.
As I said before, you don't need braces, but braces are necessary.
If you look at them as a group, they are used regularly. For example, if, for, and switch all support initialization statements.
Control structure in the form of
There will be details later, but overall:
The if and switch statements are presented as 1 and 2 elements, which are explained in more detail later.
The for loop has the form of 1 and 3 elements:
The 1-element form is equivalent to while:
in the C language
for a {}
The 3 element form is equivalent to for:
in the C language
var a int
var b, c *int // Pay attention to and C The different
var d []int
type S struct { a, b int }
1
In all of these forms, any element can be empty.
if
The basic form is well known, but there is no "else suspension "problem:
var a int
var b, c *int // Pay attention to and C The different
var d []int
type S struct { a, b int }
2
Supports initialization statements; You need a semicolon.
var a int
var b, c *int // Pay attention to and C The different
var d []int
type S struct { a, b int }
3
More beneficial to use with multivariate functions:
var a int
var b, c *int // Pay attention to and C The different
var d []int
type S struct { a, b int }
4
The ellipsis condition means true, which is of little use here. But it is especially useful in for, switch statements.
for
The basic form is known as
var a int
var b, c *int // Pay attention to and C The different
var d []int
type S struct { a, b int }
5
The omission condition means true:
var a int
var b, c *int // Pay attention to and C The different
var d []int
type S struct { a, b int }
6
And you can omit the semicolon:
var a int
var b, c *int // Pay attention to and C The different
var d []int
type S struct { a, b int }
7
Don't forget multiple assignments:
for i,j := 0,N; i < j; i,j = i+1,j-1 { ... }
There is no comma operator in Go as there is in C
switch details
switch is somewhat similar to switch in C.
However, there are some important differences in syntax and semantics:
- expressions do not have to be constant, or even int.
- there is no automatic fall through
- but instead, syntactically, the final statement can be fallthrough
- multiple case can be separated by a comma
switch count%7 {
case 4,5,6: error()
case 3: a *= v; fallthrough
case 2: a *= v; fallthrough
case 1: a *= v; fallthrough
case 0: return a*v
}
Switch
switch in Go is far more powerful than C. Common form:
switch a {
case 0: fmt.Printf("0")
default: fmt.Printf("non-zero")
}
The switch expression can be of any type; if it is null, true is indicated. The result is similar to an if-else chain:
a, b := x[i], y[j]
switch {
case a < b: return -1
case a == b: return 0
case a > b: return 1
}
Or
if a == b { return true } else { return false }
for i = 0; i < 10; i++ { ... }
2
Break, continue and
The break and continue statements work similarly to those in C.
They can specify an label and affect the outer structure:
Loop: for i := 0; i < 10; i++ {
switch f(i) {
case 0, 1, 2: break Loop
}
g(i)
}
Yes, that's an goto.
x, function
The function begins with the func keyword.
If there is a return type, the return type is placed after the parameter. return means exactly what you would expect.
func square(f float64) float64 { return f*f }
Functions can return multiple values. Thus, the return type is a bracketed list.
func MySqrt(f float64) (float64, bool) {
if f >= 0 { return math.Sqrt(f), true }
return 0, false
}
empty identifier
What if you only care about the first value returned by the MySqrt function? You still need to put the second value in one place.
Solution: use an empty identifier _(underscore). It is pre-declared and can be assigned any useless value.
// Don't care about boolean from MySqrt.
val, _ = MySqrt(foo())
In other USES of the empty identifier, we will still display it.
function
with the result variable (result variable)
If you name the result parameter, you can use it as an actual variable.
func MySqrt(f float64) (v float64, ok bool) {
if f >= 0 { v,ok = math.Sqrt(f), true }
else { v,ok = 0,false }
return v,ok
}
The resulting variable is initialized to "0"(0, 0.0,false, etc.). According to its type; More on that later)
func MySqrt(f float64) (v float64, ok bool) {
if f >= 0 { v,ok = math.Sqrt(f), true }
return v,ok
}
null returns
Finally, an return that does not return an expression returns the current value of the result variable. Here are two other versions of MySqrt:
func MySqrt(f float64) (v float64, ok bool) {
if f >= 0 { v,ok = math.Sqrt(f), true }
return // must be explicit
}
func MySqrt(f float64) (v float64, ok bool) {
if f < 0 { return } // error case
return math.Sqrt(f),true
}
What is 0
The memory in Go is initialized. All variables are initialized when the previous declaration is executed. If there is no explicit initialization expression, we will use the "0 value "of the corresponding type. The following loop:
for i := 0; i < 5; i++ {
var v int
fmt.Printf("%d ", v)
v = 5
}
I'm going to print 0, 0, 0, 0, 0.
The value of 0 depends on the type: the value is 0; Boolean is false; The empty string is ""; Pointer, map, slice, channel is nil; The structure is 0 and so on.
Defer
The defer statement is responsible for executing a function (or method) when its function returns. The parameter is evaluated at the moment it reaches the defer statement; Its function is executed on return.
package main
const three = 3
var i int = three
func main() { fmt.Printf("%d\n", i) }
1
Useful in closing file descriptors, unlocking mutex, and so on.
One function
is executed per Defer
Go performs a set of defer functions in last in first out (LIFO) order.
package main
const three = 3
var i int = three
func main() { fmt.Printf("%d\n", i) }
2
The above code will output 4, 3, 2, 1, 0. You can close all file descriptors and unlock all mutexes at the end.
Trace code with defer:
package main
const three = 3
var i int = three
func main() { fmt.Printf("%d\n", i) }
3
But we can do it a little bit more subtly.
The parameter is evaluated immediately, defer executes
later
func trace(s string) string {
fmt.Println("entering:", s)
return s
}
func un(s string) {
fmt.Println("leaving:", s)
}
func a() {
defer un(trace("a"))
fmt.Println("in a")
}
func b() {
defer un(trace("b"))
fmt.Println("in b")
a()
}
func main() { b() }
letter number par value
As in C, functions cannot be declared inside functions. But a literal numeric value can be assigned to a variable.
func f() {
for i := 0; i < 10; i++ {
g := func(i int) { fmt.Printf("%d",i) }
g(i)
}
}
The numeric value of the letter is the closure (closure)
A function numeric value is actually a closure.
package main
const three = 3
var i int = three
func main() { fmt.Printf("%d\n", i) }
6
Output 1 21 321 and add x to f.