Complex types in the Go language are described in detail
- 2020-05-05 11:22:03
- OfStack
The golang composite types include: structs, arrays, slices, and Maps.
1, array
Array
Arrays in golang are very different from arrays in C and more like arrays in Pascal. (Slice, next topic, something like an array in C)
var ar [3]int
Declare ar to be an array of three integers, with all elements initialized to 0.
Size is a component of a type.
The built-in function len can be used to get the array size:
len(ar) = 3
The array is of value type
Arrays in golang are values, not implicit Pointers in C. You can get the address of the array and generate a pointer to the array (for example, pass it efficiently to a function) :
func f(a [3]int) { fmt.Println(a) }
func fp(a *[3]int) { fmt.Println(a) }
func main() {
var ar [3] int
f(ar) // Pass a ar A copy of the
fp(&ar) // Pass a point ar A pointer to the
}
Output:
[0 0 0]
&[0 0 0]
array literals
All conformance types have the same value creation syntax. Take arrays, for example, with the syntax:
An array of three integers:
[3]int{1, 2, 3}
An array of 10 integers whose first three elements are not 0:
[10]int{ 1, 2, 3}
Don't want to count? The use of... Represents length:
[...]int{1, 2, 3}
Don't want to initialize all the values? Use key:value versus:
[10]int{2:1, 3:1, 5:1, 7:1}
pointer
to the array literalYou can get the address of the array literal and get a pointer to the new array instance:
func fp(a *[3]int) { fmt.Println(a) }
func main() {
for i := 0; i < 3; i++ {
fp(&[3]int{i, i*i, i*i*i})
}
}
Output:
&[0 0 0]
&[1 1 1]
&[2 4 8]
2, slice (Slice)
Slice
A slice is a reference to a segment of an array.
Slices are used more and more widely than regular arrays.
Slicing is cheap to use.
A slice type is much like an array type with no size:
var a []int
The built-in len(a) returns the number of elements in the slice.
By "slicing" an array or slice, we can create a new slice:
a = ar[7:9]
The valid subvalues of a(a in the above example) are 0 and 1; len (a) = = 2.
slicing shorthand
When slicing an array, the first TAB defaults to 0:
ar[:n] is equivalent to a[0:n].
The second lower value defaults to len(array/slice) :
ar[n:] is equivalent to ar[n:len(ar)].
So when slicing by the array:
ar[:] is equivalent to ar[0:len(ar)].
slice reference array
Conceptually:
type Slice struct {
base *elemType // Point to the 0th Pointer to element
len int // The number of elements in a slice
cap int // A slice can contain the number of elements
}
Array:
ar : 7 1 5 4 3 8 7 2 11 5 3
Chip:
len(ar) = 3
4
creates slices
The slice literal looks like an array literal with no specified size:
len(ar) = 3
5
The code above creates an array of length 5 and creates a slice to reference the array.
We can use the built-in make function to assign a slice (the underlying function is actually an array) :
len(ar) = 3
6
Why make instead of new? Because we need to create slices, not just to allocate memory. Note that make([]int, 10) returns []int, while new([]int) returns *[]int.
Create slices using make, map, and channel.
slice capacity
A slice is a reference to the underlying array. So there are elements in the array that are not in the range of the slice reference.
The built-in function cap(capacity) reports how long a slice may grow.
len(ar) = 3
7
len(a) = 2, cap(a) = 5, now we can slice again:
len(ar) = 3
8
len(a) is now 4, while cap(a) is still 5.
adjust slice size
Slices can be used as growable arrays. Assign a slice using make and specify its length and capacity. When we want to grow, we can do a re-slice:
len(ar) = 3
9
Thus, the length of sl is always the number of elements, but its capacity can be increased as needed.
This technique is very inexpensive and is a common practice in Go.
Slicing is very cheap to use
You are free to distribute and adjust the slice size as needed. They are passed on at a small cost; You don't have to assign.
Remember that they are references, so the underlying storage can be modified.
For example, I/O USES slicing instead of counting:
func Read(fd int, b []byte) int
var buffer [100]byte
for i := 0; i < 100; i++ {
// Every time to Buffer Is filled with a byte
Read(fd, buffer[i:i+1]) // no allocation here
}
Split an Buffer:
header, data := buf[:n], buf[n:]
Strings can also be sliced, and with similar efficiency.
3, Maps
maps
Map is another reference type. They are declared like this:
var m map[string]float64
An map is declared here, with the index key of type string and the value type float64. This is similar to the type in C++ *map< string, float64 > .
For a given map m, len(m) returns the number of key.
map creation
As with creating a slice, an map variable is an empty reference; You should put something into it before you can use it.
Three ways:
1) literal: comma-separated key:value pair list
m = map[string]float64{"1":1, "pi":3.1415}
2) create
m = make(map[string]float64) // make not new
3) assignment
var m1 map[string]float64
m1 = m // m1 and m Now quote the same map
map index
(the next few examples all use:
m = map[string]float64{"1":1, "pi":3.1415})
Access an element; If the element does not exist, you get the zero value of the corresponding map value type:
one := m["1"]
zero := m["not present"] // zero Be set to 0.0.
Set the value of an element (setting it twice will update it to the latest value)
m["2"] = 2
m["2"] = 3 // confusion
tests for existence
To test the existence of an key in an map, we can use a form of "comma, om" with multiple assignments:
m = map[string]float64{"1":1, "pi":3.1415}
var value float64
var present bool
value, present = m[x]
Or as usual:
value, ok := m[x] // "comma ok" In the form of
If x and key exist in map, the Boolean variable will be set to true; value will be assigned the corresponding value of key in map. Instead, the Boolean variable is set to false, and value is set to zero of the corresponding value type.
delete
A value in map,
, can be deleted using a multivariate assignment
[0 0 0]
&[0 0 0]
1
If the value of keep is true, then v is assigned to map. If keep is false, key x in map is deleted. So delete an key:
[0 0 0]
&[0 0 0]
2
The deletion method described above in Go 1 has been removed and delete(m, x) has been replaced.
for and range
For arrays, slices, and map (and more types we'll see in part 3), the for loop provides a special syntax for iterating through its elements.
[0 0 0]
&[0 0 0]
3
With just one variable, we can get key:
[0 0 0]
&[0 0 0]
4
Variables can be assigned or declared with :=.
For arrays and slices, this way we get the index of the element and the value of the element.
USES range for the string
When for range is used for strings, the actual element iterated is the Unicode code point (code point), not the byte (for bytes, you can use []byte or the standard for statement). We assume the string package
Contains characters encoded with UTF-8.
Next loop:
[0 0 0]
&[0 0 0]
5
Output: 0:'[' 1:'ÿ' 3:' bound '6:']'
If the wrong UTF-8 code point is encountered, the character is set to U+FFFD, with the subscript moved back one byte.
4, Structs
structs
You should be familiar with struct in Go: simple data field declarations.
[0 0 0]
&[0 0 0]
6
More commonly used:
[0 0 0]
&[0 0 0]
7
struct allows programmers to define memory layouts.
struct is the value type
struct is the value type, new(StructType) returns a pointer to a zero value (allocated memory is set to zero).
type Point struct {
x, y float64
}
var p Point
p.x = 7
p.y = 23.4
var pp *Point = new(Point)
*pp = p
pp.x = Pi // (*pp).x The syntactic sugar
For struct Pointers, there is no -> Symbols are available. Go provides an indirect approach.
creates the structure
Structs are value types, so you can create a full 0 struct variable just by declaring it.
You can also use new to create a structure.
var p Point // Zero value
pp := new(Point) // idioms
The struct literal syntax is also as expected:
p = Point{7.2, 8.4}
p = Point{y:8.4, x:7.2}
pp = &Point{7.2, 8.4} // idioms
pp = &Point{} // It's also customary, == new(Point)
As with arrays, you get the address of the structure literal, and you get the address of the new structure.
These examples are constructors.
export type and field
The structure can only be visible outside the package if the first letter of the name of the field of the structure (and method, which we will cover) is capitalized.
Private types and fields:
type point struct { x, y float64 }
Export type and field:
[3]int{1, 2, 3}
2
Export type and private type mixed fields:
type Point struct {
X, Y float64 // exported
name string // not exported
}
You can even create a private type with an export field. Exercise: when will it come in handy?
anonymous field
In a structure, you can declare fields without names, such as another structure type. These fields are called anonymous fields. They look like inner structures simply inserted or "embedded" into the
Like the outer structure.
This simple mechanism provides a way to inherit existing implementations from other types.
Here's an example.
An anonymous struct field :
type A struct {
ax, ay int
}
type B struct {
A
bx, by float64
}
B looks like it has four fields ax, ay, bx, and by. B can be viewed as {ax, ay int; bx, by float64}.
Then the literal value of B must provide details:
b := B{A{1, 2}, 3.0, 4.0}
fmt.Println(b.ax, b.ay, b.bx, b.by)
Output 1, 2, 3, 4
The anonymous field takes the type as the name
Anonymous fields are more than simply inserting them, they have more meaning: B also has the field A. An anonymous field looks like a field whose name is its type name.
b := B{A{ 1, 2}, 3.0, 4.0}
fmt.Println(b.A)
Output: {1, 2}. If A comes from another package, this field is still called A.
import "pkg"
type C struct { pkg.A }
...
c := C {pkg.A{1, 2}}
fmt.Println(c.A) // not c.pkg.A
anonymous field of any type
Any named type or pointer to a named type can be used as an anonymous field. They can appear anywhere in the structure.
type C struct {
x float64
int
string
}
c := C{3.5, 7, "hello"}
fmt.Println(c.x, c.int, c.string)
Output: 3.5 7 hello
conflicts and veils
If there are two fields with the same name (possibly the name of an inheritance type), the code follows the following rule:
1) cover the name of the outer layer with the name of the inner layer. This provides a way to override fields/methods.
2) if the same name appears at the same level, it will be an error if the name is used. (no errors if not used)
Ambiguity is something that no rule can solve and must be fixed.
conflict example
type A struct { a int }
type B struct { a, b int }
type C struct { A; B }
var c C
An error will occur using c.a. Is it c. A. a or c. B. a?
type D struct { B; b float64 }
var d D
Using d. b no problem: it is float64 type variable, not d. B. b. To get the inner b, available d. B. b.