Language characteristics
Simple deployment:
- It can be directly compiled into machine code for execution
- Do not rely on other libraries
- Run directly to deploy
- Statically typed languages: hidden problems can be detected at compile time
- Concurrency at the language level: it naturally supports concurrency and makes full use of multi-core
Powerful standard library:
- runtime system scheduling mechanism
- Efficient GC garbage collection
- Rich standard library
- Easy to learn: 25 keywords, support embedded C syntax, object-oriented and cross platform
configuration setup
Mac download address: https://dl.google.com/go/go1....
Installation path: / usr/local/go
Configure environment variables:
vi ~/.bash_profile
export GOPATH=$HOME/go
source ~/.bash_profile
common problem
1.go.mod file not found in current directory or any parent directory
Solution: go env -w GO111MODULE=auto
Grammatical attention
- Semicolons are not recommended at the end of expressions
Import multiple packages
import ( "fmt" "time" )
- Curly braces for a function must go with the function name
vim hello.go
package main import "fmt" func main() { fmt.Println("Hello Go!") }
Compile and execute
go run hello.go
compile
go build hello.go
implement
./hello
Variable var
Declare a variable (default is 0)
var a int
Declare a variable and initialize a value
var b int = 100
The type is omitted during initialization, and the data type is automatically matched through the value (not recommended)
var c = 100 var cc = "abcd" fmt.Printf("cc=%s,cc=%T",cc,cc)//cc=abcd,cc=string
Omit the var keyword and automatically match (common)
e := 100 f := "abcd"
Note: Method 1.2.3 can declare global variables outside the function; 4 local variables can only be declared in function bodies
Declare multiline variables
var xx, yy int = 100, 200 var mm, nn = 100, "abc" var ( cc int = 100 dd bool = true ) fmt.Println("cc=",cc,"dd=",dd)
Constant const
Constants are not allowed to be modified
const a int = 100 const ( BEIJING = 1 SHANGHAI = 2 )
iota: used in conjunction with const. Each line is accumulated. The first line defaults to 0
const ( BEIJING = 10 * iota //0 SHANGHAI //10 SHENZHEN //20 ) const ( a, b = iota+1,iota+2//iota=0, a=1, b=2 c, d //iota=1, c=1, d=3 g, h = iota*2,iota*3//iota=3, g=6, h=9 )
function
Basic function form
func test(a string, b int) int { return 100 }
Multiple return values
//anonymous func test(a string, b int) (int, int) { return 666, 777 } //There is a formal parameter name (initialization defaults to 0) func test(a string, b int) (r1 int, r2 int) { r1 = 1000 r2 = 2000 return }
import and init
hello.go
package main import ( "GoStudy/lib1" "GoStudy/lib2" ) func main() { lib1.Lib1Test(); //Function names called externally must be capitalized lib2.Lib2Test(); } //Output results //lib1.init()... //lib2.init()... //Lib1Test()... //Lib2Test()...
lib1/lib1.go
package lib1 import "fmt" func Lib1Test() { fmt.Println("Lib1Test()...") } func init() { fmt.Println("lib1.init()...") }
lib2/lib2.go
package lib2 import "fmt" func Lib2Test() { fmt.Println("Lib2Test()...") } func init() { fmt.Println("lib2.init()...") }
be careful:
Import an anonymous package (do not execute the functions in the package, but execute the init method)
import _ "GoStudy/lib2"
Import package alias
import l2 "GoStudy/lib2" func main() { l2.Lib2Test(); }
Import into the current package (function can be called directly)
import . "GoStudy/lib2" func main() { Lib2Test(); }
Pointer*
package main import "fmt" func changeValue(p *int) { *p = 10; } func main() { var a = 1 changeValue(&a) //p = &a //*p = 10 fmt.Println("a =",a) //a = 10 }
defer
The mechanism to execute before the end of the function (first in, then out, after the return method)
package main import "fmt" func func1() { fmt.Println("func1()...") } func func2() { fmt.Println("func2()...") } func func3() { fmt.Println("func3()...") } func returnAndDefer() int { defer func1() defer func2() defer func3() return returnFunc() } func returnFunc() int { fmt.Println("returnFunc()...") return 0 } func main() { returnAndDefer() } //Execution sequence: returnFunc()... func3()... func2()... func1()...
Array and dynamic array
Fixed length array
package main import "fmt" func test(arr []int) { arr[0] = 111 } func main() { //Fixed length array var myArr []int //Array traversal test(myArr)//myArr[0] unchanged for k, v := range myArr2 { fmt.Println("index=",k,"value=",v) } }
Dynamic array (slice)
Dynamic array is passed by reference. In fact, what is passed is an array pointer pointing to the same block of memory
Dynamic array parameters of different lengths are the same
package main import "fmt" func test(arr []int) { arr[0] = 111 } func main() { //Fixed length array myArr := []int{1,2,3,4} //Array traversal test(myArr)//myArr[0] unchanged for k, v := range myArr { fmt.Println("index=",k,"value=",v) } } //Output results index= 0 value= 111 index= 1 value= 2 index= 2 value= 3 index= 3 value= 4
Note:_ Represents an anonymous variable
Declaration of slices
Declare slice1 as a slice and initialize it. The default value is 1,2,3 and the length len is 3
slice1 := []int{1, 2, 3}
Declare slice2 as a slice, but no space is allocated. make is required to allocate space (the initialization value is 0)
var slice2 = []int slice2 = make([]int, 3)
Declare slice3 as a slice and allocate space through make (the initialization value is 0)
var slice3 []int = make([]int, 3)
Declare slice4 as a slice and allocate space through make (the initialization value is 0). Deduce slice4 as a slice through: = (common)
slice4 := make([]int, 3)
Addition of slices
len: length, indicating the distance from the left pointer to the right pointer
cap: capacity, indicating the distance from the left pointer to the end of the underlying array
Capacity expansion mechanism of slice: when append, if the length increases and exceeds the capacity, the capacity will be doubled (5 - > 10 - > 20)
var numbers = make([]int, 3, 5)//Length 3, capacity 5 fmt.Printf("len=%d,cap=%d,slice=%v",len(numbers),cap(numbers),numbers) //len=3,cap=5,slice=[0 0 0]
Append an element 1 to numbers
numbers = append(numbers, 1) fmt.Printf("len=%d,cap=%d,slice=%v",len(numbers),cap(numbers),numbers) //len=4,cap=5,slice=[0 0 0 1]
Append an element 2 to numbers
numbers = append(numbers, 2) fmt.Printf("len=%d,cap=%d,slice=%v",len(numbers),cap(numbers),numbers) //len=5,cap=5,slice=[0 0 0 1 2]
Append element to slice with full capacity
numbers = append(numbers, 3) fmt.Printf("len=%d,cap=%d,slice=%v",len(numbers),cap(numbers),numbers) //len=6,cap=10,slice=[0 0 0 1 2 3]
Slice interception
s := []int{1,2,3} s1 := s[0:2] s2 := make([]int, 3) copy(s2, s)//copy the values in s to s2 s1[0] = 100 fmt.Println(s)//[100 2 3] fmt.Println(s1)//[100 2] fmt.Println(s2)//[1 2 3]
map
Declaration method
Mode 1:
- Declare that myMap1 is a map type, key is string and value is string
- Before using a map, you need to allocate data space to the map with make
var myMap1 map[string]string myMap1 = make(map[string]string, 10) myMap1["a"] = "aaa" myMap1["b"] = "bbb"
Mode 2:
myMap2 := make(map[int]string) myMap2[0] = "a" myMap2[1] = "b" fmt.Println(myMap2) //map[0:a 1:b]
Mode III
myMap3 := map[int]string { 0 : "a", 1 : "b", } fmt.Println(myMap3) //map[0:a 1:b]
Mode of use
map is also passed by reference. When making parameters, the pointer address is passed
add to
myMap2 := make(map[int]string) myMap2[0] = "a" myMap2[1] = "b"
ergodic
for k, v := range myMap2 { fmt.Printf("k=%d,v=%s\n",k,v) }
delete
delete(myMap2, 0)
modify
myMap2[0] = "c"
object-oriented
structural morphology
definition
type Book struct { title string //Class's property is capitalized to indicate public, otherwise it is private auth string }
use
var book1 Book book1.title = "Golang" book1.auth = "Tom" fmt.Println(book1)//{Golang Tom} book2 := Book{title:"aaa",auth:"bbb"} fmt.Println(book2)//{aaa bbb} book3 := Book{"aaa","bbb"} fmt.Println(book3)//{aaa bbb}
Pass (copy passed)
func changeBook(book Book) { book.title="XXX" } func main() { var book1 Book book1.title = "Golang" book1.auth = "Tom" changeBook(book1) fmt.Println(book1)//{Golang Tom} }
class
Encapsulation: class name, property name and method name are capitalized to indicate external access
this is a copy of the object that called the method
func (this *Book) setName(title string) { this.title=title } func (this Book) setAuth(auth string) { this.auth=auth } func main() { book := Book{title:"aaa",auth:"bbb"} book.setName("ccc") book.setAuth("ddd") fmt.Println(book)//{ccc bbb} }
inherit
package main import "fmt" type Human struct { name string sex string } type SuperMan struct { Human level int } func (this *Human) Eat() { fmt.Println("Human Eat...") } func (this *Human) Walk() { fmt.Println("Human Walk...") } func (this *SuperMan) Walk() { fmt.Println("SuperMan Walk...") } func (this *SuperMan) Fly() { fmt.Println("SuperMan Fly...") } func main() { tom := Human{"aaa","bbb"} tom.Eat() //Human Eat... tom.Walk()//Human Walk... //s :=SuperMan{Human{"ccc","ddd"},100} var s SuperMan s.name = "Sss" s.sex = "man" s.level= 88 s.Walk()//SuperMan Walk... s.Fly()//SuperMan Fly... }
polymorphic
interface is essentially a pointer to the parent class
Basic elements:
- There is a parent class (Interface)
- A subclass implements all the interface methods of the parent class
- The variable (pointer) of the parent type points to (references) the specific data variable of the child class
package main import "fmt" type AnimalIF interface { Sleep() GetColor() string } type Cat struct { color string } func (this *Cat) Sleep() { fmt.Println("Cat Sleep...") } func (this *Cat) GetColor() string { return this.color } type Dog struct { color string } func (this *Dog) Sleep() { fmt.Println("Dog Sleep...") } func (this *Dog) GetColor() string { return this.color } func showAnimal(animal AnimalIF) { animal.Sleep() fmt.Println("color=",animal.GetColor()) } func main() { var animal AnimalIF//Data type of interface: parent class pointer animal = &Cat{"White"} animal.Sleep()//Cat Sleep... fmt.Println("color=",animal.GetColor())//color= White dog := Dog{"Yellow"} showAnimal(&dog) //Dog Sleep... //color= Yellow }
Universal data type interface {} (empty interface)
interface {} type assertion mechanism: arg.(string)
package main import "fmt" type Book struct { tile string } func test(arg interface{}){ fmt.Println(arg) //Assert _, ok := arg.(string) if !ok { fmt.Println("arg is not string") }else{ fmt.Println("arg is string") } } func main() { book := Book{"Golang"} test(book)//{Golang} test(123)//123 test("hello")//hello }
Variable type
Variable pair
type
- static type: int/string
- concrete type: the specific data type referred to by interaction (the type visible to the system runtime)
- value
package main import "fmt" type Reader interface { ReadBook() } type Writer interface { WriteBook() } type Book struct { } func (this *Book) ReadBook() { fmt.Println("Read a book.") } func (this *Book) WriteBook() { fmt.Println("Write a book.") } func main() { b := &Book{}//b: Pair < type: book, value: Book {} address > var r Reader//r: Pair < type: empty, value: empty > r = b //r: Pair < type: book, value: Book {} address > r.ReadBook() var w Writer w = r.(Writer)//w: Pair < type: book, value: Book {} address > //There are two steps to assert: get the dynamic type type and judge whether the type implements the target interface. //The assertion here succeeds because the type is book, and Book implements the Writer interface w.WriteBook() }
Reflection
Example 1:
package main import ( "fmt" "reflect" ) func reflectNum(arg interface{}){ fmt.Println("type:", reflect.TypeOf(arg)) fmt.Println("value:", reflect.ValueOf(arg)) } func main() { var num float64 = 1.34556 reflectNum(num) //type: float64 //value: 1.34556 }
Example 2:
package main import ( "fmt" "reflect" ) type User struct { Id int Name string Age int } func (this User) Call(){ fmt.Printf("User: %v", this) } func DoFieldAndMethod(input interface{}){ inputType := reflect.TypeOf(input) inputValue := reflect.ValueOf(input) //traversal attributes for i := 0; i < inputType.NumField(); i++ { field := inputType.Field(i) value := inputValue.Field(i).Interface() fmt.Printf("%s:%v = %v\n",field.Name, field.Type, value) } //Id:int //Name:string = Lilei //Age:int = 18 //Traversal method (note that the structure method of pointer type cannot be printed) for i := 0; i < inputType.NumMethod(); i++ { inputMethod := inputType.Method(i) fmt.Printf("%s:%v\n",inputMethod.Name, inputMethod.Type) } //Call:func(main.User) } func main() { user := User{1, "Lilei", 18} DoFieldAndMethod(user) }
Structure tagtag
package main import ( "fmt" "reflect" ) type User struct { Name string `info:"name" doc:"full name"` Age int `info:"age" doc:"Age"` } func findTag(input interface{}){ inputType := reflect.TypeOf(input).Elem() //traversal attributes for i := 0; i < inputType.NumField(); i++ { taginfo := inputType.Field(i).Tag.Get("info") tagdoc := inputType.Field(i).Tag.Get("doc") fmt.Printf("info:%s doc:%s\n",taginfo, tagdoc) } } func main() { var u User findTag(&u) //info:name doc: name //info:age doc: age }
Application of structure tag in json
package main import ( "fmt" "encoding/json" ) type User struct { Name string `json:"name"` Age int `json:"age"` Hobby []string `json:"hobby"` } func main() { user := User{"lilei", 18, []string{"dance","football"}} //json encoding jsonStr, err := json.Marshal(user) if err != nil { fmt.Println("Json marshal error.") return } fmt.Printf("json = %s",jsonStr)//json = {"name":"lilei","age":18,"hobby":["dance","football"]} //json decoding user1 := User{} err = json.Unmarshal(jsonStr, &user1) if err != nil { fmt.Println("Json unmarshal error.") return } fmt.Println(user1)//{lilei 18 [dance football]} }