Go Note
- Go Quick Start
Go Quick Start
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ go version
go version go1.15.5 darwin/amd64
// run the file
$ go build main.go
// main
$ ./main
$ go build -o hello main.go
// hello
$ ./hello
$ ls -la
total 8440
drwxrwxr-x@ 5 luo staff 160 Nov 29 20:26 .
drwxrwxr-x@ 20 luo staff 640 Dec 13 2018 ..
-rwxr-xr-x 1 luo staff 2155416 Nov 29 20:26 hello
-rwxr-xr-x 1 luo staff 2155416 Nov 29 20:24 main
-rw-rw-r--@ 1 luo staff 78 Dec 13 2018 main.go
code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
package main // same as the file name
import (
// format, bring the output to the console
"fmt"
)
// -------------------- variables --------------------
func main() {
fmt.Printf("Hello, World!")
fmt.Printf("Hello, World!") // semicolon not required
var name = "Bill"
fmt.Printf("Hello, %s!", name)
names := "Bob"
fmt.Printf("Hello, %s!", names)
}
// -------------------- const --------------------
var (
name string
)
func main() {
const pi = 3.14
name = "Bill"
fmt.Printf("Hello, %s %v !\n", name, pi)
}
// -------------------- composite --------------------
var (
name [1]string
)
const (
pi = 3.14
)
func main() {
name[0] = "Bill"
fmt.Printf("Hello, %s %v !\n", name[0], pi)
}
// -------------------- slices --------------------
var (
name = []string{"Bill", "Ted", "Frank"}
)
const (
pi = 3.14
)
func main() {
fmt.Printf("Hello, %s %v !\n", name[1:2], pi)
fmt.Printf("Hello, %s %v !\n", name[:2], pi)
fmt.Printf("Hello, %s %v !\n", name, pi)
name = append(name, "Jenny")
fmt.Printf("Hello, %s %v !\n", name, pi)
}
// -------------------- map --------------------
var (
level = map[string]int{
"Bill": 25,
"Ted": 1,
"Frank": 8,
}
)
func main() {
fmt.Printf("Hello, Bill you are level %v !\n", level["Bill"])
}
// -------------------- structs --------------------
// Car defines a car
type Car struct {
wheels int
color string
}
func main() {
var camaro Car
camaro.wheels = 4
camaro.color = "Black"
fmt.Printf("Your Camaro has %v wheels and is %s.", camaro.wheels, camaro.color)
}
// -------------------- if else --------------------
func main() {
level := 25
var response string
if level > 20 && level < 30 {
response = "High level"
} else if level <= 20 {
response = "Low level"
} else {
response = "Super High level"
}
fmt.Printf("Your level is %s.", response)
}
// -------------------- for loop --------------------
func main() {
for x := 1; x < 4; x++ {
fmt.Printf("print a line %v\n", x)
}
nums := []int{1, 2, 3}
for x := range nums {
fmt.Printf("print line %v\n", x)
}
// for index, value := range nums {
for x, y := range nums {
fmt.Printf("print index %v, num %v\n", x, y)
}
for _, y := range nums {
fmt.Printf("print value %v\n", y)
}
}
// -------------------- for/while loop --------------------
func main() {
num := 1
for num <= 3 {
fmt.Printf("print line %v\n", num)
num++
}
}
// -------------------- input --------------------
func main() {
var input string
for {
fmt.Printf("Enter your name:")
fmt.Scanln(&input)
if input == "stop" {
break
} else {
fmt.Printf("You Entered: %v", input)
fmt.Println("You Entered:", input)
break
}
}
}
// -------------------- case --------------------
func main() {
fmt.Println("Select an option:")
fmt.Println("1. Add numbers")
fmt.Println("2. Subtract numbers")
fmt.Println("3. Multiply numbers")
fmt.Println("4. Divide numbers")
result, _ := fmt.Scanln()
if result == 1 {
// do something
} else if result == 2 {
// do something
} else if result == 3 {
// do something
} else if result == 4 {
// do something
} else {
// go back an incorrect response
}
fmt.Println("Select an option:")
fmt.Println("1. Add numbers")
fmt.Println("2. Subtract numbers")
fmt.Println("3. Multiply numbers")
fmt.Println("4. Divide numbers")
switch result, _ := fmt.Scanln();
result {
case 1:
// do something
case 2:
// do something
case 3:
// do something
case 4:
// do something
default:
// go back an incorrect response
}
}
// -------------------- function --------------------
func sayhello(name string) {
fmt.Printf("Hello, %s!\n", name)
}
func main() {
name := "Bill"
sayhello(name)
}
func sayhello(name string, age int) {
fmt.Printf("Hello, %s you are %v years old!\n", name, age)
}
func main() {
name := "Bill"
age := 21
sayhello(name, age)
}
// -------------------- return value --------------------
func sayhello(name string, age int) string {
result := fmt.Sprintf("Hello, %s you are %v years old!\n", name, age)
return result
}
func main() {
name := "Bill"
age := 21
message := sayhello(name, age)
fmt.Printf(message)
}
// -------------------- validate --------------------
import (
"errors"
"fmt"
)
func sayhello(name string, age int) (string, error) {
result := ""
if len(name) > 5 {
return result, errors.New("Your name is too long")
}
result = fmt.Sprintf("Hello, %s you are %v years old!\n", name, age)
return result, nil
}
func main() {
name := "William"
age := 21
message, err := sayhello(name, age)
if err != nil {
fmt.Println(err)
}
fmt.Printf(message)
}
// -------------------- error --------------------
if err := myFun(value); err != nil {
return nil, err
log.Fatal(err)
log.Println("Error occur %v", err)
os.Exit(1)
panic(err)
http.Error(w, msg, http.StatusInternalServerError)
}
Golang Arrays
array
- data structure that consists of a collection of elements of a single type or a special variable, which can hold more than one value at a time.
- The values an array holds are called its
elements
oritems
. - An array holds a specific number of elements, and it cannot grow or shrink.
- Different data types can be handled as elements in arrays such as
Int, String, Boolean, and others
. - The index of the first element of any dimension of an array is 0.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package main
import (
"fmt"
"reflect"
)
// Declaring an Array
func main() {
var intArray [5]int
var strArray [5]string
fmt.Println(reflect.ValueOf(intArray).Kind())
fmt.Println(reflect.ValueOf(strArray).Kind())
// array
// array
}
// Assign and Access Values
func main() {
var theArray [3]string
theArray[0] = "India" // Assign a value to the first element
theArray[1] = "Canada" // Assign a value to the second element
theArray[2] = "Japan" // Assign a value to the third element
fmt.Println(theArray[0]) // Access the first element value
fmt.Println(theArray[1]) // Access the second element value
fmt.Println(theArray[2]) // Access the third element value
// Output
// India
// Canada
// Japan
}
// Initializing an Array with an Array Literal
func main() {
x := [5]int{10, 20, 30, 40, 50} // Initialized with values
var y [5]int = [5]int{10, 20, 30} // Partial assignment
fmt.Println(x)
fmt.Println(y)
// Output
// [10 20 30 40 50]
// [10 20 30 0 0]
}
// Initializing an Array with ellipses...
// - use ... instead of specifying the length.
// - The compiler can identify the length of an array, based on the elements specified in the array declaration.
func main() {
x := [...]int{10, 20, 30}
fmt.Println(reflect.ValueOf(x).Kind())
fmt.Println(len(x))
// Output
// array
// 3
}
// Initializing Values for Specific Elements
// values can be initialize for specific elements.
func main() {
x := [5]int{1: 10, 3: 30}
fmt.Println(x)
// Output
// [0 10 0 30 0]
}
// Loop Through an Indexed Array
func main() {
intArray := [5]int{10, 20, 30, 40, 50}
fmt.Println("\n---------------Example 1--------------------\n")
for i := 0; i < len(intArray); i++ {
fmt.Println(intArray[i])
}
fmt.Println("\n---------------Example 2--------------------\n")
for index, element := range intArray {
fmt.Println(index, "=>", element)
}
fmt.Println("\n---------------Example 3--------------------\n")
for _, value := range intArray {
fmt.Println(value)
}
j := 0
fmt.Println("\n---------------Example 4--------------------\n")
for range intArray {
fmt.Println(intArray[j])
j++
}
}
// Copy Array
// create copy of an array, by assigning an array to a new variable either by value or reference.
func main() {
strArray1 := [3]string{"Japan", "Australia", "Germany"}
strArray2 := strArray1 // data is passed by value
strArray3 := &strArray1 // data is passed by reference
fmt.Printf("strArray1: %v\n", strArray1)
fmt.Printf("strArray2: %v\n", strArray2)
strArray1[0] = "Canada"
fmt.Printf("strArray1: %v\n", strArray1)
fmt.Printf("strArray2: %v\n", strArray2)
fmt.Printf("*strArray3: %v\n", *strArray3)
// strArray1: [Canada Australia Germany]
// strArray2: [Japan Australia Germany]
// *strArray3: [Canada Australia Germany]
}
// Check if Element Exists
func main() {
strArray := [5]string{"India", "Canada", "Japan", "Germany", "Italy"}
fmt.Println(itemExists(strArray, "Canada"))
fmt.Println(itemExists(strArray, "Africa"))
// Output
// true
// false
}
func itemExists(InfoList interface{}, item interface{}) bool {
arr := reflect.ValueOf(InfoList)
if arr.Kind() != reflect.Array {
panic("Invalid data-type")
}
for i := 0; i < arr.Len(); i++ {
if arr.Index(i).Interface() == item {
return true
}
}
return false
}
// Filter Array Elements
func main() {
countries := [...]string{"India", "Canada", "Japan", "Germany", "Italy"}
fmt.Printf("Countries: %v\n", countries)
fmt.Printf(":2 %v\n", countries[:2])
fmt.Printf("1:3 %v\n", countries[1:3])
fmt.Printf("2: %v\n", countries[2:])
fmt.Printf("2:5 %v\n", countries[2:5])
fmt.Printf("0:3 %v\n", countries[0:3])
fmt.Printf("Last element: %v\n", countries[len(countries)-1])
fmt.Printf("All elements: %v\n", countries[0:len(countries)])
fmt.Println(countries[:])
fmt.Println(countries[0:])
fmt.Println(countries[0:len(countries)])
fmt.Printf("Last two elements: %v\n", countries[len(countries)-2:len(countries)])
// Output
// Countries: [India Canada Japan Germany Italy]
// :2 [India Canada]
// 1:3 [Canada Japan]
// 2: [Japan Germany Italy]
// 2:5 [Japan Germany Italy]
// 0:3 [India Canada Japan]
// Last element: Italy
// All elements: [India Canada Japan Germany Italy]
// [India Canada Japan Germany Italy]
// [India Canada Japan Germany Italy]
// [India Canada Japan Germany Italy]
// Last two elements: [Germany Italy]
}
Golang Slices
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
package main
import (
"fmt"
"reflect"
)
// Create Empty Slice
func main() {
var intSlice []int
var strSlice []string
fmt.Println(reflect.ValueOf(intSlice).Kind())
fmt.Println(reflect.ValueOf(strSlice).Kind())
// Output
// slice
// slice
}
// Declare Slice using Make
// Slice can be created using the built-in function make.
// When you use make, one option you have is to specify the length of the slice.
// When you just specify the length, the capacity of the slice is the same.
func main() {
var intSlice = make([]int, 10) // when length and capacity is same
var strSlice = make([]string, 10, 20) // when length and capacity is different
fmt.Printf("intSlice \tLen: %v \tCap: %v\n", len(intSlice), cap(intSlice))
fmt.Println(reflect.ValueOf(intSlice).Kind())
fmt.Printf("strSlice \tLen: %v \tCap: %v\n", len(strSlice), cap(strSlice))
fmt.Println(reflect.ValueOf(strSlice).Kind())
// Output
// intSlice Len: 10 Cap: 10
// slice
// strSlice Len: 10 Cap: 20
// slice
}
// Initialize Slice with values using a Slice Literal
func main() {
var intSlice = []int{10, 20, 30, 40}
var strSlice = []string{"India", "Canada", "Japan"}
}
// Declare Slice using new Keyword
// A slice can be declare using new keyword followed by capacity in square brackets then type of elements the slice will hold.
func main() {
var intSlice = new([50]int)[0:10]
fmt.Println(reflect.ValueOf(intSlice).Kind())
fmt.Printf("intSlice \tLen: %v \tCap: %v\n", len(intSlice), cap(intSlice))
fmt.Println(intSlice)
// Output
// slice
// intSlice Len: 10 Cap: 50
// [0 0 0 0 0 0 0 0 0 0]
}
// Add Items
func main() {
a := make([]int, 2, 5)
a[0] = 10
a[1] = 20
fmt.Println("Slice A:", a)
fmt.Printf("Length is %d Capacity is %d\n", len(a), cap(a))
// Output
// Slice A: [10 20]
// Length is 2 Capacity is 5
a = append(a, 30, 40, 50, 60, 70, 80, 90)
fmt.Println("Slice A after appending data:", a)
fmt.Printf("Length is %d Capacity is %d\n", len(a), cap(a))
// Slice A after appending data: [10 20 30 40 50 60 70 80 90]
// Length is 9 Capacity is 12
}
// Access Items
func main() {
var intSlice = []int{10, 20, 30, 40}
fmt.Println(intSlice[0])
fmt.Println(intSlice[1])
fmt.Println(intSlice[0:4])
}
// Change Item Value
func main() {
var strSlice = []string{"India", "Canada", "Japan"}
strSlice[2] = "Germany"
}
// Remove Item from Slice
// RemoveIndex function created to remove specific item from String slice.
func main() {
var strSlice = []string{"India", "Canada", "Japan", "Germany", "Italy"}
strSlice = RemoveIndex(strSlice, 3)
fmt.Println(strSlice)
// Output
// [India Canada Japan Germany Italy]
// [India Canada Japan Italy]
}
func RemoveIndex(s []string, index int) []string {
return append(s[:index], s[index+1:]...)
// - use ... instead of specifying the length.
// - The compiler can identify the length of an array, based on the elements specified in the array declaration.
}
// Copy a Slice
// The built-in copy function is used to copy data from one slice to another.
func main() {
a := []int{5, 6, 7} // Create a smaller slice
fmt.Printf("[Slice:A] Length is %d Capacity is %d\n", len(a), cap(a))
// [Slice:A] Length is 3 Capacity is 3
b := make([]int, 5, 10) // Create a bigger slice
copy(b, a) // Copy function
fmt.Printf("[Slice:B] Length is %d Capacity is %d\n", len(b), cap(b))
fmt.Println("Slice B after copying:", b)
// [Slice:B] Length is 5 Capacity is 10
// Slice B after copying: [5 6 7 0 0]
b[3] = 8
b[4] = 9
fmt.Println("Slice B after adding elements:", b)
// Slice B after adding elements: [5 6 7 8 9]
}
// Tricks of Slicing
// Slicing is a computationally fast way to methodically access parts of your data.
func main() {
var countries = []string{"india", "japan", "canada", "australia", "russia"}
fmt.Printf("Countries: %v\n", countries)
fmt.Printf(":2 %v\n", countries[:2])
fmt.Printf("1:3 %v\n", countries[1:3])
fmt.Printf("2: %v\n", countries[2:])
fmt.Printf("2:5 %v\n", countries[2:5])
fmt.Printf("0:3 %v\n", countries[0:3])
fmt.Printf("Last element: %v\n", countries[4])
fmt.Printf("Last element: %v\n", countries[len(countries)-1])
fmt.Printf("Last element: %v\n", countries[4:])
fmt.Printf("All elements: %v\n", countries[0:len(countries)])
fmt.Printf("Last two elements: %v\n", countries[3:len(countries)])
fmt.Printf("Last two elements: %v\n", countries[len(countries)-2:len(countries)])
fmt.Println(countries[:])
fmt.Println(countries[0:])
fmt.Println(countries[0:len(countries)])
}
// Output
// Countries: [india japan canada australia russia]
// :2 [india japan]
// 1:3 [japan canada]
// 2: [canada australia russia]
// 2:5 [canada australia russia]
// 0:3 [india japan canada]
// Last element: russia
// Last element: russia
// Last element: [russia]
// All elements: [india japan canada australia russia]
// Last two elements: [australia russia]
// Last two elements: [australia russia]
// [india japan canada australia russia]
// [india japan canada australia russia]
// [india japan canada australia russia]
// Loop Through a Slice
func main() {
var strSlice = []string{"India", "Canada", "Japan", "Germany", "Italy"}
fmt.Println("\n---------------Example 1 --------------------\n")
for index, element := range strSlice {
fmt.Println(index, "--", element)
}
fmt.Println("\n---------------Example 2 --------------------\n")
for _, value := range strSlice {
fmt.Println(value)
}
j := 0
fmt.Println("\n---------------Example 3 --------------------\n")
for range strSlice {
fmt.Println(strSlice[j])
j++
}
}
// Append a slice to an existing slice
func main() {
var slice1 = []string{"india", "japan", "canada"}
var slice2 = []string{"australia", "russia"}
slice2 = append(slice2, slice1...)
}
// Check if Item Exists
func main() {
var strSlice = []string{"India", "Canada", "Japan", "Germany", "Italy"}
fmt.Println(itemExists(strSlice, "Canada"))
fmt.Println(itemExists(strSlice, "Africa"))
}
func itemExists(infollist interface{}, item interface{}) bool {
s := reflect.ValueOf(infollist)
if s.Kind() != reflect.Slice {
panic("Invalid data-type")
}
for i := 0; i < s.Len(); i++ {
if s.Index(i).Interface() == item {
return true
}
}
return false
}
Golang Maps
A map is a data structure that provides you with an unordered collection of key/value pairs (maps are also sometimes called associative arrays in Php, hash tables in Java, or dictionaries in Python). Maps are used to look up a value by its associated key. You store values into the map based on a key.
The strength of a map is its ability to retrieve data quickly based on the key. A key works like an index, pointing to the value you associate with that key.
A map is implemented using a hash table, which is providing faster lookups on the data element and you can easily retrieve a value by providing the key.
- Maps are unordered collections, and there’s no way to predict the order in which the key/value pairs will be returned.
- Every iteration over a map could return a different order.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package main
import "fmt"
// Map initialization
func main() {
var employee = map[string]int{"Mark": 10, "Sandy": 20}
fmt.Println(employee)
}
// Empty Map declaration
// Map employee created having string as key-type and int as value-type
func main() {
var employee = map[string]int{}
fmt.Println(employee) // map[]
fmt.Printf("%T\n", employee) // map[string]int
}
// Map declaration using make function
// The make function takes as argument the type of the map and it returns an initialized map.
func main() {
var employee = make(map[string]int)
employee["Mark"] = 10
employee["Sandy"] = 20
fmt.Println(employee)
// map[Mark:10 Sandy:20]
employeeList := make(map[string]int)
employeeList["Mark"] = 10
employeeList["Sandy"] = 20
fmt.Println(employeeList)
// map[Mark:10 Sandy:20]
}
// Map Length
func main() {
var employee = make(map[string]int)
employee["Mark"] = 10
employee["Sandy"] = 20
// Empty Map
employeeList := make(map[string]int)
fmt.Println(len(employee)) // 2
fmt.Println(len(employeeList)) // 0
}
// Accessing Items
func main() {
var employee = map[string]int{"Mark": 10, "Sandy": 20}
fmt.Println(employee["Mark"])
}
// Adding Items
func main() {
var employee = map[string]int{"Mark": 10, "Sandy": 20}
employee["Rocky"] = 30 // Add element
employee["Josef"] = 40
}
// Update Values
func main() {
var employee = map[string]int{"Mark": 10, "Sandy": 20}
employee["Mark"] = 50 // Edit item
}
// Delete Items
func main() {
var employee = make(map[string]int)
employee["Mark"] = 10
employee["Sandy"] = 20
employee["Rocky"] = 30
employee["Josef"] = 40
delete(employee, "Mark")
}
// Iterate over a Map
func main() {
var employee = map[string]int{"Mark": 10, "Sandy": 20,"Rocky": 30, "Rajiv": 40, "Kate": 50}
for key, element := range employee {
fmt.Println("Key:", key, "=>", "Element:", element)
}
}
// Truncate Map
// There are two methods to clear all items from a Map.
func main() {
var employee = map[string]int{"Mark": 10, "Sandy": 20, "Rocky": 30, "Rajiv": 40, "Kate": 50}
// Method - I
for k := range employee {
delete(employee, k)
}
// Method - II
employee = make(map[string]int)
}
// Sort Map Keys
func main() {
unSortedMap := map[string]int{"India": 20, "Canada": 70, "Germany": 15}
keys := make([]string, 0, len(unSortedMap))
for k := range unSortedMap {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Println(k, unSortedMap[k])
}
}
// Sort Map Values
func main() {
unSortedMap := map[string]int{"India": 20, "Canada": 70, "Germany": 15}
// Int slice to store values of map.
values := make([]int, 0, len(unSortedMap))
for _, v := range unSortedMap {
values = append(values, v)
}
// Sort slice values.
sort.Ints(values)
// Print values of sorted Slice.
for _, v := range values {
fmt.Println(v)
}
}
// Merge Maps
func main() {
first := map[string]int{"a": 1, "b": 2, "c": 3}
second := map[string]int{"a": 1, "e": 5, "c": 3, "d": 4}
for k, v := range second {
first[k] = v
}
}
Golang Struct
A struct (short for “structure”) is a collection of data fields with declared data types. Golang has the ability to declare and create own data types by combining one or more types, including both built-in and user-defined types. Each data field in a struct is declared with a known type, which could be a built-in type or another user-defined type.
Structs are the only way to create concrete user-defined types in Golang. Struct types are declared by composing a fixed set of unique fields. Structs can improve modularity and allow to create and pass complex data structures around the system. You can also consider Structs as a template for creating a data record, like an employee record or an e-commerce product.
- The declaration starts with the keyword
type
, then a name for the new struct, and finally the keywordstruct
. Within the curly brackets, a series of data fields are specified with a name and a type.
1
2
3
4
5
type identifier struct{
field1 data_type
field2 data_type
field3 data_type
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
package main
import "fmt"
// Declaration of a Struct Type
type rectangle struct {
length float64
breadth float64
color string
}
func main() {
fmt.Println(rectangle{10.5, 25.10, "red"})
}
// Creating Instances of Struct Types
type rectangle struct {
length int
breadth int
color string
geometry struct {
area int
perimeter int
}
}
func main() {
var rect rectangle // dot notation
rect.length = 10
rect.breadth = 20
rect.color = "Green"
rect.geometry.area = rect.length * rect.breadth
rect.geometry.perimeter = 2 * (rect.length + rect.breadth)
fmt.Println(rect)
fmt.Println("Area:\t", rect.geometry.area)
fmt.Println("Perimeter:", rect.geometry.perimeter)
}
// Creating a Struct Instance Using a Struct Literal
type rectangle struct {
length int
breadth int
color string
}
func main() {
var rect1 = rectangle{10, 20, "Green"}
var rect2 = rectangle{length: 10, color: "Green"} // breadth value skipped
rect3 := rectangle{10, 20, "Green"}
rect4 := rectangle{length: 10, breadth: 20, color: "Green"}
rect5 := rectangle{breadth: 20, color: "Green"} // length value skipped
}
// Struct Instantiation Using new Keyword
type rectangle struct {
length int
breadth int
color string
}
func main() {
rect1 := new(rectangle) // rect1 is a pointer to an instance of rectangle
rect1.length = 10
rect1.breadth = 20
rect1.color = "Green"
fmt.Println(rect1)
var rect2 = new(rectangle) // rect2 is an instance of rectangle
rect2.length = 10
rect2.color = "Red"
fmt.Println(rect2)
}
// Two instances of the rectangle struct are instantiated,
// rect1 points to the address of the instantiated struct
// rect2 is the name of a struct it represents.
// Struct Instantiation Using Pointer Address Operator
// Creates an instance of rectangle struct by using a pointer address operator is denoted by & symbol.
type rectangle struct {
length int
breadth int
color string
}
func main() {
var rect1 = &rectangle{10, 20, "Green"} // Can't skip any value
fmt.Println(rect1)
var rect2 = &rectangle{}
rect2.length = 10
rect2.color = "Red"
fmt.Println(rect2) // breadth skipped
var rect3 = &rectangle{}
(*rect3).breadth = 10
(*rect3).color = "Blue"
fmt.Println(rect3) // length skipped
}
// Nested Struct Type
// Struct can be nested by creating a Struct type using other Struct types as the type for the fields of Struct. Nesting one struct within another can be a useful way to model more complex structures.
type Salary struct {
Basic, HRA, TA float64
}
type Employee struct {
FirstName, LastName, Email string
Age int
MonthlySalary []Salary
}
func main() {
e := Employee{
FirstName: "Mark",
LastName: "Jones",
Email: "mark@gmail.com",
Age: 25,
MonthlySalary: []Salary{
Salary{
Basic: 15000.00,
HRA: 5000.00,
TA: 2000.00,
},
Salary{
Basic: 16000.00,
HRA: 5000.00,
TA: 2100.00,
},
Salary{
Basic: 17000.00,
HRA: 5000.00,
TA: 2200.00,
},
},
}
fmt.Println(e.FirstName, e.LastName)
fmt.Println(e.Age)
fmt.Println(e.Email)
fmt.Println(e.MonthlySalary[0])
fmt.Println(e.MonthlySalary[1])
fmt.Println(e.MonthlySalary[2])
}
// Use Field Tags in the Definition of Struct Type
// During the definition of a struct type, optional string values may be added to each field declaration.
import (
"fmt"
"encoding/json"
)
type Employee struct {
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
City string `json:"city"`
}
func main() {
json_string := `
{
"firstname": "Rocky",
"lastname": "String",
"city": "London"
}`
emp1 := new(Employee)
json.Unmarshal([]byte(json_string), emp1)
fmt.Println(emp1)
// &{Rocky String London}
emp2 := new(Employee)
emp2.FirstName = "Ramesh"
emp2.LastName = "Soni"
emp2.City = "Mumbai"
jsonStr, _ := json.Marshal(emp2)
fmt.Printf("%s\n", jsonStr)
// {"firstname":"Ramesh","lastname":"Soni","city":"Mumbai"}
}
// The tags are represented as raw string values (wrapped within a pair of ``) and ignored by normal code execution.
// Add Method to Struct Type
// You can also add methods to struct types using a method receiver. A method EmpInfo is added to the Employee struct.
type Salary struct {
Basic, HRA, TA float64
}
type Employee struct {
FirstName, LastName, Email string
Age int
MonthlySalary []Salary
}
func (e Employee) EmpInfo() string {
fmt.Println(e.FirstName, e.LastName)
fmt.Println(e.Age)
fmt.Println(e.Email)
for _, info := range e.MonthlySalary {
fmt.Println("===================")
fmt.Println(info.Basic)
fmt.Println(info.HRA)
fmt.Println(info.TA)
}
return "----------------------"
}
func main() {
e := Employee{
FirstName: "Mark",
LastName: "Jones",
Email: "mark@gmail.com",
Age: 25,
MonthlySalary: []Salary{
Salary{
Basic: 15000.00,
HRA: 5000.00,
TA: 2000.00,
},
Salary{
Basic: 16000.00,
HRA: 5000.00,
TA: 2100.00,
},
Salary{
Basic: 17000.00,
HRA: 5000.00,
TA: 2200.00,
},
},
}
fmt.Println(e.EmpInfo())
}
// Assign Default Value for Struct Field
// Method of assigning a custom default value can be achieve by using constructor function. Instead of creating a struct directly, the Info function can be used to create an Employee struct with a custom default value for the Name and Age field.
// This is a technique rather than something that is part of the Golang specification.
type Employee struct {
Name string
Age int
}
func (obj *Employee) Info() {
if obj.Name == "" {
obj.Name = "John Doe"
}
if obj.Age == 0 {
obj.Age = 25
}
}
func main() {
emp1 := Employee{Name: "Mr. Fred"}
emp1.Info()
fmt.Println(emp1)
emp2 := Employee{Age: 26}
emp2.Info()
fmt.Println(emp2)
}
// Find Type of Struct
// The reflect package support to check the underlying type of a struct.
type rectangle struct {
length float64
breadth float64
color string
}
func main() {
var rect1 = rectangle{10, 20, "Green"}
fmt.Println(reflect.TypeOf(rect1)) // main.rectangle
fmt.Println(reflect.ValueOf(rect1).Kind()) // struct
rect2 := rectangle{length: 10, breadth: 20, color: "Green"}
fmt.Println(reflect.TypeOf(rect2)) // main.rectangle
fmt.Println(reflect.ValueOf(rect2).Kind()) // struct
rect3 := new(rectangle)
fmt.Println(reflect.TypeOf(rect3)) // *main.rectangle
fmt.Println(reflect.ValueOf(rect3).Kind()) // ptr
var rect4 = &rectangle{}
fmt.Println(reflect.TypeOf(rect4)) // *main.rectangle
fmt.Println(reflect.ValueOf(rect4).Kind()) // ptr
}
// Comparing Structs with the Different Values Assigned to Data Fields
// Structs of the same type can be compared using comparison operator.
type rectangle struct {
length float64
breadth float64
color string
}
func main() {
var rect1 = rectangle{10, 20, "Green"}
rect2 := rectangle{length: 20, breadth: 10, color: "Green"}
if rect1 == rect2 {
fmt.Println("True")
} else {
fmt.Println("False")
}
// False
rect2 := rectangle{length: 10, breadth: 20, color: "Green"}
if rect1 == rect2 {
fmt.Println("True")
} else {
fmt.Println("False")
}
// True
rect3 := new(rectangle)
var rect4 = &rectangle{}
if rect3 == rect4 {
fmt.Println("True")
} else {
fmt.Println("False")
}
// False
}
// Copy Struct Type Using Value and Pointer Reference
type rectangle struct {
length float64
breadth float64
color string
}
func main() {
r1 := rectangle{10, 20, "Green"}
r2 := r1
r2.color = "Pink"
// r2 will be the same as r1, it is a copy of r1 rather than a reference to it.
// Any changes made to r2 will not be applied to r1 and vice versa.
r3 := &r1
r3.color = "Red"
// When r3 is updated, the underlying memory that is assigned to r1 is updated.
}
Golang Interface
An Interface is an abstract type.
Interface describes all the methods of a method set and provides the signatures for each method.
To create interface use interface keyword, followed by curly braces containing a list of method names, along with any parameters or return values the methods are expected to have.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
// Declare an Interface Type and methods does not have a body
type Employee interface {
PrintName() string // Method with string return type
PrintAddress(id int) // Method with int parameter
PrintSalary(b int, t int) float64 // Method with parameters and return type
}
// Define Type that Satisfies an Interface
// - Defines Employee interface with two methods.
// - defines Emp type that satisfies Employee.
// - defines methods on Emp that it needs to satisfy Employee
// - If a type has all the methods declared in an interface, then no further declarations needed explicitly to say that Emp satisfies **Employee**.
// - Declares an _e1_ variable with **Employee** as its type, then creates a Emp value and assigns it to _e1_.
// Employee is an interface for printing employee details
type Employee interface {
PrintName(name string)
PrintSalary(basic int, tax int) int
}
// Emp user-defined type
type Emp int
// PrintName method to print employee name
func (e Emp) PrintName(name string) {
fmt.Println("Employee Id:\t", e)
fmt.Println("Employee Name:\t", name)
}
// PrintSalary method to calculate employee salary
func (e Emp) PrintSalary(basic int, tax int) int {
var salary = (basic * tax) / 100
return basic - salary
}
func main() {
var e1 Employee
e1 = Emp(1)
e1.PrintName("John Doe")
fmt.Println("Employee Salary:", e1.PrintSalary(25000, 5))
// Employee Id: 1
// Employee Name: John Doe
// Employee Salary: 23750
}
// Define Type that Satisfies Multiple Interfaces
// - Interfaces allows any user-defined type to satisfy multiple interface types at once.
// - Using **Type Assertion** you can get a value of a concrete type back and you can call methods on it that are defined on other interface, but aren't part of the interface satisfying.
type Polygons interface {
Perimeter()
}
type Object interface {
NumberOfSide()
}
type Pentagon int
func (p Pentagon) Perimeter() {
fmt.Println("Perimeter of Pentagon", 5*p)
}
func (p Pentagon) NumberOfSide() {
fmt.Println("Pentagon has 5 sides")
}
func main() {
var p Polygons = Pentagon(50)
p.Perimeter()
var o Pentagon = p.(Pentagon)
o.NumberOfSide()
var obj Object = Pentagon(50)
obj.NumberOfSide()
var pent Pentagon = obj.(Pentagon)
pent.Perimeter()
}
// When a user-defined type implements the set of methods declared by an interface type, values of the user-defined type can be assigned to values of the interface type.
// This assignment stores the value of the user-defined type into the interface value.
// When a method call is made against an interface value, the equivalent method for the stored user-defined value will be executed.
// Since any user-defined type can implement any interface, method calls against an interface value are polymorphic in nature.
// The user-defined type in this relationship is often referred as **concrete type**.
// Interfaces with common Method
// Two or more interfaces can have one or more common method in list of method sets.
// Here, **Structure** is a common method between two interfaces Vehicle and Human.
type Vehicle interface {
Structure() []string // Common Method
Speed() string
}
type Human interface {
Structure() []string // Common Method
Performance() string
}
type Car string
type Man string
func (c Car) Structure() []string {
var parts = []string{"ECU", "Engine", "Air Filters", "Wipers", "Gas Task"}
return parts
}
func (c Car) Speed() string {
return "200 Km/Hrs"
}
func (m Man) Structure() []string {
var parts = []string{"Brain", "Heart", "Nose", "Eyelashes", "Stomach"}
return parts
}
func (m Man) Performance() string {
return "8 Hrs/Day"
}
func main() {
var bmw Vehicle
bmw = Car("World Top Brand")
var labour Human
labour = Man("Software Developer")
for i, j := range bmw.Structure() {
fmt.Printf("%-15s <=====> %15s\n", j, labour.Structure()[i])
}
// Output
// ECU <=====> Brain
// Engine <=====> Heart
// Air Filters <=====> Nose
// Wipers <=====> Eyelashes
// Gas Task <=====> Stomach
}
// Interface Accepting Address of the Variable
// The Print() methods accept a receiver pointer. Hence, the interface must also accept a receiver pointer.
// _If a method accepts a type value, then the interface must receive a type value; if a method has a pointer receiver, then the interface must receive the address of the variable of the respective type._
type Book struct {
author, title string
}
type Magazine struct {
title string
issue int
}
type Printer interface {
Print()
}
func (b *Book) Assign(n, t string) {
b.author = n
b.title = t
}
func (b *Book) Print() {
fmt.Printf("Author: %s, Title: %s\n", b.author, b.title)
}
func (m *Magazine) Assign(t string, i int) {
m.title = t
m.issue = i
}
func (m *Magazine) Print() {
fmt.Printf("Title: %s, Issue: %d\n", m.title, m.issue)
}
func main() {
var b Book
// Declare instance of Book
var m Magazine
// Declare instance of Magazine
b.Assign("Jack Rabbit", "Book of Rabbits")
// Assign values to b via method
m.Assign("Rabbit Weekly", 26)
// Assign values to m via method
var i Printer // Declare variable of interface type
fmt.Println("Call interface")
i = &b // Method has pointer receiver, interface does not
i.Print() // Show book values via the interface
i = &m // Magazine also satisfies shower interface
i.Print() // Show magazine values via the interface
}
// Empty Interface Type
// The type interface{} is known as the **empty interface**, and it is used to accept values of any type. The empty interface doesn't have any methods that are required to satisfy it, and so every type satisfies it.
func printType(i interface{}) {
fmt.Println(i)
}
func main() {
var manyType interface{}
manyType = 100
fmt.Println(manyType)
// 100
manyType = 200.50
fmt.Println(manyType)
// 200.5
manyType = "Germany"
fmt.Println(manyType)
// Germany
printType("Go programming language")
// Go programming language
var countries = []string{"india", "japan", "canada", "australia", "russia"}
printType(countries)
// [india japan canada australia russia]
var employee = map[string]int{"Mark": 10, "Sandy": 20}
printType(employee)
// map[Mark:10 Sandy:20]
country := [3]string{"Japan", "Australia", "Germany"}
printType(country)
// [Japan Australia Germany]
}
// The manyType variable is declared to be of the type interface{} and it is able to be assigned values of different types. The printType() function takes a parameter of the type interface{}, hence this function can take the values of any valid type.
// Polymorphism
// Polymorphism is the ability to write code that can take on different behavior through the implementation of types.
// We have the declaration of a structs named Pentagon, Hexagon, Octagon and Decagon with the implementation of the **Geometry** interface.
// Geometry is an interface that defines Geometrical Calculation
type Geometry interface {
Edges() int
}
// Pentagon defines a geometrical object
type Pentagon struct{}
// Hexagon defines a geometrical object
type Hexagon struct{}
// Octagon defines a geometrical object
type Octagon struct{}
// Decagon defines a geometrical object
type Decagon struct{}
// Edges implements the Geometry interface
func (p Pentagon) Edges() int { return 5 }
// Edges implements the Geometry interface
func (h Hexagon) Edges() int { return 6 }
// Edges implements the Geometry interface
func (o Octagon) Edges() int { return 8 }
// Edges implements the Geometry interface
func (d Decagon) Edges() int { return 10 }
// Parameter calculate parameter of object
func Parameter(geo Geometry, value int) int {
num := geo.Edges()
calculation := num * value
return calculation
}
// main is the entry point for the application.
func main() {
p := new(Pentagon)
h := new(Hexagon)
o := new(Octagon)
d := new(Decagon)
g := [...]Geometry{p, h, o, d}
for _, i := range g {
fmt.Println(Parameter(i, 5))
}
// 25
// 30
// 40
// 50
}
// We have our polymorphic Edges functions that accepts values that implement the **Geometry** interface. Using polymorphic approach the method created here Parameter is used by each concrete type value that's passed in.
// Interface Embedding
// Interfaces may embed other interfaces, this behavior is an aspect of interface polymorphism which is known as **ad hoc polymorphism**.
type Geometry interface {
Edges() int
}
type Polygons interface {
Geometry // Interface embedding another interface
}
type Pentagon int
type Hexagon int
type Octagon int
type Decagon int
func (p Pentagon) Edges() int { return 5 }
func (h Hexagon) Edges() int { return 6 }
func (o Octagon) Edges() int { return 8 }
func (d Decagon) Edges() int { return 10 }
func Parameter(geo Geometry, value int) int {
num := geo.Edges()
calculation := num * value
return calculation
}
func main() {
p := new(Pentagon)
h := new(Hexagon)
o := new(Octagon)
d := new(Decagon)
polygons := [...]Polygons{p, h, o, d}
for i := range polygons {
fmt.Println(polygons[i].Edges())
}
g := [...]Geometry{p, h, o, d}
for _, i := range g {
fmt.Println(Parameter(i, 5))
}
}
package
flag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//生成 命令行参数 对应的变量,变量为指针类型
// var objectName = flag.String("ParameterName", "DefaultValueX", "Help information")
// ./test -ParameterName=(DefaultValueX/inputValue)
// ./test --help
// Usage of ./test:
// -ParameterName string
// Help information (default DefaultValueX)
var name = flag.String("name", "Tom", "Input your name")
var age = flag.Int("age", 18, "Input your age")
var vip = flag.Bool("flag", true, "Is VIP")
// 其中"name","age","flag"对应在命令行中通过如下格式指定参数
-name=Jack
-name Jack
--name=Jack
--name Jack
// 定义值类型的 命令行参数 变量,xxxVar对其进行初始化。可以为Int,String,Bool
// var postCode = flag.Int("Postcode", 1234, "Input your post code")
var postCode int
flag.IntVar(&postCode, "Postcode", 1234, "Input your post code")
//接受命令行参数
flag.Parse()
//返回没有被解析的命令行参数的个数
flag.NArg()
//返回没有被解析的命令行参数
flag.Args()
//命令行设置的参数个数
flag.NFlag()
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package main
import (
"flag"
"fmt"
)
var name = flag.String("name", "Tom", "Input your name")
var age = flag.Int("age", 18, "Input your age")
var f = flag.Bool("isVIP", false, "Is VIP")
var postCode int
func init() {
flag.IntVar(&postCode, "postcode", 1234, "Input your post code")
}
func main() {
flag.Parse()
fmt.Println("name:", *name)
fmt.Println("age:", *age)
fmt.Println("VIP:", *f)
fmt.Println("postCode:", postCode)
fmt.Println("tail:", flag.Args())
fmt.Println(flag.NArg())
fmt.Println(flag.NFlag())
args := os.Args
fmt.Println("Args:", args)
paramCnt := flag.NArg()
for cnt := 0; cnt < paramCnt; cnt++ {
fmt.Println(flag.Arg(cnt))
}
}
// 执行测试
$ ./test \
-name=Bill \
-age=22 \
-isVIP=true \
-postcode=3235 otherParam1 otherParam2
// name: Bill
// age: 22
// VIP: true
// postCode: 3235
// tail: [otherParam1 otherParam2]
// 2
// 4
// Args: [./clitest -name=Bill -age=22 -isVIP=true --postcode=3235 otherParam1 otherParam2]
// otherParam1
// otherParam2
JSON and Go
Encoding
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func Marshal(v interface{}) ([]byte, error)
// Given the Go data structure, `Message`,
type Message struct {
Name string
Body string
Time int64
}
// an instance of `Message`
m := Message{"Alice", "Hello", 1294706395881547000}
// marshal a JSON-encoded version of m using `json.Marshal`:
b, err := json.Marshal(m)
// If all is well,
// `err` will be `nil`
// `b` will be a `[]byte` containing this JSON data:
b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
Only data structures that can be represented as valid JSON will be encoded:
JSON objects only support strings as keys; to encode a Go map type it must be of the form
map[string]T
(whereT
is any Go type supported by the json package).Channel, complex, and function types cannot be encoded.
Cyclic data structures are not supported; they will cause
Marshal
to go into an infinite loop.Pointers will be encoded as the values they point to (or ‘null’ if the pointer is
nil
).
The json package only accesses the exported fields of struct types (those that begin with an uppercase letter). Therefore only the exported fields of a struct will be present in the JSON output.
Decoding
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func Unmarshal(data []byte, v interface{}) error
// create a place where the decoded data will be stored
var m Message
// call `json.Unmarshal`, passing it a `[]byte` of JSON data and a pointer to `m`
err := json.Unmarshal(b, &m)
// If `b` contains valid JSON that fits in `m`, after the call `err` will be `nil` and the data from `b` will have been stored in the struct `m`, as if by an assignment like:
m = Message{
Name: "Alice",
Body: "Hello",
Time: 1294706395881547000,
}
How does Unmarshal
identify the fields in which to store the decoded data?
For a given JSON key
"Foo"
,Unmarshal
will look through the destination struct’s fields to find (in order of preference):An exported field with a tag of
"Foo"
An exported field named
"Foo"
, orAn exported field named
"FOO"
or"FoO"
or some other case-insensitive match of"Foo"
.
if the structure of the JSON data doesn’t exactly match the Go type?
1
2
3
b := []byte(`{"Name":"Bob","Food":"Pickle"}`)
var m Message
err := json.Unmarshal(b, &m)
Unmarshal
will decode only the fields that it can find in the destination type. In this case, only the Name field of m will be populated, and the Food field will be ignored. This behavior is particularly useful when you wish to pick only a few specific fields out of a large JSON blob. It also means that any unexported fields in the destination struct will be unaffected by Unmarshal
.
But what if you don’t know the structure of your JSON data beforehand?
Generic JSON with interface
The interface{}
(empty interface) type describes an interface with zero methods. Every Go type implements at least zero methods and therefore satisfies the empty interface.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main
import (
"fmt"
// "math"
)
func main() {
var i interface{}
i = "a string"
i = 2011
i = 2.777
// A type assertion accesses the underlying concrete type:
// r := i.(float64)
// fmt.Println("the circle's area", math.Pi*r*r)
// Or, if the underlying type is unknown, a type switch determines the type:
switch v := i.(type) {
case int:
fmt.Println("twice i is", v*2)
case float64:
fmt.Println("the reciprocal of i is", 1/v)
case string:
h := len(v) / 2
fmt.Println("i swapped by halves is", v[h:]+v[:h])
default:
// it isn't one of the types above
}
}
The json package uses map[string]interface{}
and []interface{}
values to store arbitrary JSON objects and arrays; it will happily unmarshal any valid JSON blob into a plain interface{}
value. The default concrete Go types are:
bool
for JSON booleans,float64
for JSON numbers,string
for JSON strings, andnil
for JSON null.
Decoding arbitrary data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// Consider this JSON data, stored in the variable `b`:
b := []byte(`{"Name":"Wednesday","Age":6,"Parents":["Gomez","Morticia"]}`)
// Without knowing this data’s structure,
// we can decode it into an `interface{}` value with `Unmarshal`:
var f interface{}
err := json.Unmarshal(b, &f)
// At this point the Go value in `f` would be a map whose keys are strings and whose values are themselves stored as empty interface values:
f = map[string]interface{}{
"Name": "Wednesday",
"Age": 6,
"Parents": []interface{}{
"Gomez",
"Morticia",
},
}
// To access this data we can use a type assertion to access `f`’s underlying `map[string]interface{}`:
m := f.(map[string]interface{})
// We can then iterate through the map with a range statement and use a type switch to access its values as their concrete types:
for k, v := range m {
switch vv := v.(type) {
case string:
fmt.Println(k, "is string", vv)
case float64:
fmt.Println(k, "is float64", vv)
case []interface{}:
fmt.Println(k, "is an array:")
for i, u := range vv {
fmt.Println(i, u)
}
default:
fmt.Println(k, "is of a type I don't know how to handle")
}
}
// In this way you can work with unknown JSON data while still enjoying the benefits of type safety.
Reference Types
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// Let’s define a Go type to contain the data from the previous example:
type FamilyMember struct {
Name string
Age int
Parents []string
}
var m FamilyMember
err := json.Unmarshal(b, &m)
// Unmarshaling that data into a `FamilyMember` value works as expected,
// but if we look closely we can see a remarkable thing has happened.
// With the var statement we allocated a `FamilyMember` struct, and then provided a pointer to that value to `Unmarshal`, but at that time the `Parents` field was a `nil` slice value.
// To populate the `Parents` field, `Unmarshal` allocated a new slice behind the scenes. This is typical of how `Unmarshal` works with the supported reference types (pointers, slices, and maps).
Consider unmarshaling into this data structure:
type Foo struct {
Bar *Bar
}
// If there were a `Bar` field in the JSON object, `Unmarshal` would allocate a new `Bar` and populate it. If not, `Bar` would be left as a `nil` pointer.
// From this a useful pattern arises: if you have an application that receives a few distinct message types, you might define “receiver” structure like
type IncomingMessage struct {
Cmd *Command
Msg *Message
}
// and the sending party can populate the `Cmd` field and/or the `Msg` field of the top-level JSON object, depending on the type of message they want to communicate.
// `Unmarshal`, when decoding the JSON into an `IncomingMessage` struct, will only allocate the data structures present in the JSON data. To know which messages to process, the programmer need simply test that either `Cmd` or `Msg` is not `nil`.
Streaming Encoders and Decoders
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// The json package provides `Decoder` and `Encoder` types to support the common operation of reading and writing streams of JSON data.
// The `NewDecoder` and `NewEncoder` functions wrap the [`io.Reader`] and [`io.Writer`] interface types.
func NewDecoder(r io.Reader) *Decoder
func NewEncoder(w io.Writer) *Encoder
// Here’s an example program that reads a series of JSON objects from standard input, removes all but the `Name` field from each object, and then writes the objects to standard output:
package main
import (
"encoding/json"
"log"
"os"
)
func main() {
dec := json.NewDecoder(os.Stdin)
enc := json.NewEncoder(os.Stdout)
for {
var v map[string]interface{}
if err := dec.Decode(&v); err != nil {
log.Println(err)
return
}
for k := range v {
if k != "Name" {
delete(v, k)
}
}
if err := enc.Encode(&v); err != nil {
log.Println(err)
}
}
}
// Due to the ubiquity of Readers and Writers, these `Encoder` and `Decoder` types can be used in a broad range of scenarios, such as reading and writing to HTTP connections, WebSockets, or files.
inbuilt function
defer()
- used to delay the execution of a function or a statement until the nearby function returns.
- defer will move the execution of the statement to the very end inside a function.
- 用来延迟执行函数的,而且延迟发生在调用函数 return 之后,比如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package main
import "fmt"
func greet() {
defer fmt.Println("World")
fmt.Println("Hello")
}
func main() {
greet()
}
// Hello
// World
// Explanation
// invoke the greet() function, the compiler will go to `defer fmt.Println("World")`
// but since it finds the defer keyword, it will not execute it until it reaches the end of the function.
// Thus, the compiler will move to `fmt.Println("Hello")` and execute it first instead.
func main() {
defer fmt.Println("World")
defer fmt.Println("One")
defer fmt.Println("Two")
fmt.Println("Hello")
}
// Hello
// Two
// One
// World
// Explanation
// World, One, and Two will be pushed in a stack and will be executed in LIFO order before the function returns.
func a() int {
defer b()
return 0
}
// b 的执行是发生在 return 0 之后,注意 defer 的语法,关键字 defer 之后是函数的调用。
defer 的用途
- 清理释放资源
- 由于 defer 的延迟特性,defer 常用在函数调用结束之后清理相关的资源
- defer 常用来释放数据库连接,文件打开句柄等释放资源的操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
f, _ := os.Open(filename)
defer f.Close()
// 文件资源的释放会在函数调用结束之后借助 defer 自动执行,
// 不需要时刻记住哪里的资源需要释放,打开和释放必须相对应。
func CopyFile(dstName, srcName string) (written int64, err error) {
if src, err := os.Open(srcName); err != nil {
return
}
if dst, err := os.Create(dstName); err != nil { //1
return
}
written, err = io.Copy(dst, src)
dst.Close()
src.Close()
return
}
// 代码的主要目的是打开一个文件,然后复制内容到另一个新的文件中,
// 没有 defer 时这样写:代码在 #1 处返回之后,src 文件没有执行关闭操作,可能会导致资源不能正确释放,
func CopyFile(dstName, srcName string) (written int64, err error) {
if src, err := os.Open(srcName); err != nil {
return
}
defer src.Close()
if dst, err := os.Create(dstName); err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}
// 改用 defer 实现
// src 和 dst 都能及时清理和释放,无论 return 在什么地方执行。
- 执行 recover
- 被 defer 的函数在 return 之后执行,这个时机点正好可以捕获函数抛出的 panic,因而 defer 的另一个重要用途就是执行 recover。
- recover 只有在 defer 中使用才更有意义,如果在其他地方使用,由于 program 已经调用结束而提前返回而无法有效捕捉错误。
1
2
3
4
5
6
7
8
9
10
11
package main
import "fmt"
func main() {
defer func() {
if ok := recover(); ok != nil {
fmt.Println("recover")
}
}
panic("error")
}
// 记住 defer 要放在 panic 执行之前。
多个 defer 的执行顺序
- defer 的作用就是把关键字之后的函数执行压入一个栈中延迟执行
- 多个 defer 的执行顺序是后进先出 LIFO
- 这个特性可以对一个 array 实现逆序操作。
1
2
3
4
defer func() { fmt.Println("1") }()
defer func() { fmt.Println("2") }()
defer func() { fmt.Println("3") }()
// 输出顺序是 321。
被 deferred 函数的参数在 defer 时确定
- 一个函数被 defer 时,它的参数在 defer 时进行计算确定,
- 即使 defer 之后参数发生修改,对已经 defer 的函数没有影响,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
func a() {
i := 0
defer fmt.Println(i)
i++
return
}
// a 执行输出的是 0 而不是 1,
// 因为 defer 时,i 的值是 0,此时被 defer 的函数参数已经进行执行计算并确定了。
func calc(index string, a, b int) int {
ret := a + b
fmt.Println(index, a, b, ret)
return ret
}
func main() {
a := 1
b := 2
defer calc("1", a, calc("10", a, b))
a = 0
return
}
// 10 1 2 3
// 1 1 3 4
// defer 函数的参数 第三个参数在 defer 时就已经计算完成并确定,第二个参数 a 也是如此,无论之后 a 变量是否修改都不影响。
被 defer 的函数可以读取和修改带名称的返回值
1
2
3
4
5
6
func c() (i int) {
defer func() { i++ }()
return 1
}
// 被 defer 的函数是在 return 之后执行,
// 可以修改带名称的返回值,上面的函数 c 返回的是 2。
recover()
1
func recover() interface{}
- used to recover from a goroutine that is in panic,
- meaning it helps recover from an error that has been raised.
- The program takes control through recover rather than letting the code crash.
Note:
- The recover() function only works if it is called in the goroutine where panic() occurs.
- The recover() function only works when called in a deferred function.
- This is because when a panic occurs, deferred functions do not exit or crash as a normal function would.
- Hence, recover() should only be called in the deferred function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main
import "fmt"
func panicHandler(){
rec := recover()
if rec != nil {
fmt.Println("RECOVER", rec)
}
}
func employee(name *string, age int){
defer panicHandler()
if age > 65{
panic("Age cannot be greater than retirement age")
}
}
func main() {
empName := "Samia"
age := 75
employee(&empName, age)
}
Fprintf()
used to print out a formatted string to the destination of your choosing.
- Fprintf is different from the normal Fprint function, as it supports custom format specifiers and uses a format string to generate the final output string. In contrast, in Fprint, only default formats are used to format the string.
- In order to use this function, you must import the fmt package in your file and access the Fprintf function within by using the . notation: fmt.Fprintf. Here, Fprintf is the actual function, while fmt is the Go package that stores the definition of this function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main
import (
"fmt"
"bytes"
)
func main() {
// declaring variables of different datatypes
var message string = "Hello and welcome to "
var year int = 2021
// temporary buffer
var temp_buff bytes.Buffer
// printing out the declared variables as a single string
fmt.Fprintf(&temp_buff, "%s educative in %d", message, year)
fmt.Print(&temp_buff)
}
// Hello and welcome to educative in 2021
Inc()
1
2
3
4
5
6
7
8
9
10
11
type Counter interface {
Metric
Collector
// Inc increments the counter by 1.
// Use Add to increment it by arbitrary non-negative values.
Inc()
// Add adds the given value to the counter.
// It panics if the value is < 0.
Add(float64)
}
Tickers
Timers
to do something once in the futuretickers
to do something repeatedly at regular intervals.
Tickers use a similar mechanism to timers:
- a channel that is sent values.
- use the select builtin on the channel to await the values as they arrive every 500ms.
Tickers can be stopped like timers.
- Once a ticker is stopped it won’t receive any more values on its channel.
example of a ticker that ticks periodically until stop it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package main
import (
"fmt"
"time"
)
func main() {
// arrive every 500ms
ticker := time.NewTicker(500 * time.Millisecond)
done := make(chan bool)
go func() {
for {
select {
case <-done:
return
case t := <-ticker.C:
fmt.Println("Tick at", t)
}
}
}()
// stop ours after 1600ms
time.Sleep(1600 * time.Millisecond)
ticker.Stop()
done <- true
fmt.Println("Ticker stopped")
}
// the ticker should tick 3 times before we stop it.
$ go run tickers.go
// Tick at 2012-09-23 11:29:56.487625 -0700 PDT
// Tick at 2012-09-23 11:29:56.988063 -0700 PDT
// Tick at 2012-09-23 11:29:57.488076 -0700 PDT
// Ticker stopped
.
Comments powered by Disqus.