Introduction: the Go language was written by Ken Thompson, Rob Pike and Robert Griesemer. It originated in 2007 and was officially released in 2009. The main goal of Go is to "both the development speed of dynamic languages such as Python and the performance and security of compiled languages such as C/C + +". It aims to reduce the complexity of code without losing application performance. It has the advantages of "simple deployment, good concurrency, good language design and good execution performance".
Author Fu Xing
Source: Ali technical official account
preface
Once I was a developer mainly based on Java language and did java web related development. Later, I turned to Android and still couldn't do without Java until I turned to expand the front end. In fact, I've been writing business with JS. Now, due to personal development reasons, I come to Alibaba cloud and roll up the Go language due to project needs; Years of programming experience told me that language is just a tool. What matters is its thought and logic, so I just need to learn grammar. So I started Go for three days. During this period, I mainly used java and JS for analogy. The grammar changed so much that I almost gave up! In fact, it's really not good to learn grammar, which contains a lot of Go design ideas. As the saying goes, it's better to break the keyboard than to have a good memory. What I have learned still needs to be precipitated. I can also share it and discuss it together, which is more conducive to growth. So I simply recorded my notes on the introduction to Go language.
I. Introduction
The Go language was written by Ken Thompson, Rob Pike and Robert Griesemer. It originated in 2007 and was officially released in 2009. In fact, it is all Google's. The original intention of designing the Go language is to meet Google's needs. The main goal of Go is to "both the development speed of dynamic languages such as Python and the performance and security of compiled languages such as C/C + +". It aims to reduce the complexity of code without losing application performance. It has the advantages of "simple deployment, good concurrency, good language design and good execution performance". It is mainly for concurrency. Concurrency is based on goroutine. Goroutine is similar to thread, but not thread. Goroutine can be understood as a virtual thread. The Go language runtime will participate in scheduling goroutines and allocate goroutines reasonably to each CPU to maximize CPU performance.
II. Environment
We need to download JDK when playing Java. Similarly, we also need to download Go when developing with Go, which provides various development kits, libraries and compilers. Download the mac version pkg on the official website and install it directly. Finally, use the go version command to verify the version:
Then set these two environment variables. The mac system is in bash_ In the profile file:
export GOROOT=/usr/local/go export GOPATH=$HOME/go
- GOROOT: refers to the installation path of Go language compilation, tools, standard libraries, etc., which is actually equivalent to configuring JAVA_HOME.
- GOPATH: This is a little different from Java. This variable does not need to be set in Java. This indicates that the Go working directory is global. When you execute the Go command, you will rely on this directory, which is equivalent to a global workspace. Generally, $GOPATH/bin will be set to the PATH directory, so that the compiled code can be executed directly.
1 plain text development
Write code that can be saved anywhere, such as creating a new helloworld directory and creating hello Go file:
package main import "fmt" func main() { fmt.Println("hello, world") }
Then execute go build hello GO can compile the Hello file in/ Hello can be executed; Or go run hello GO into one. You do not need to set environment variables to execute this command. It looks like c, but unlike Java, you don't need a virtual machine when running. In the early GO projects, Makefile was also used to compile. Later, there were powerful commands go build and go run, which can directly identify directories or files.
2 GoLand
Auto import, super cool experience! Don't press command + /!
To run the project, you need to set build config, which is similar to Android and Java. For example, create a hello Golan project:
When importing the go module project, you need to check this item, otherwise you can't download dependencies in sync like maven/gradle:
3 VSCODE
Directly search the Go plug-in. The first one with the largest amount of installation is. I haven't used it yet, so I don't know how to install it.
III. engineering structure
When setting the GOPATH environment variable, this directory is divided into three subdirectories bin, pkg and src, which are used to store executable files, package files and source files respectively. When we execute the Go command, if we specify a directory that is not the file of the current directory or the directory of the absolute path, we will Go to the GOPATH directory to find it. In this way, after xxx directory is created in GOPATH directory, you can execute go build xx command anywhere to build or run.
pkg directory should be the package file generated after go install, including A such a file is equivalent to an archive.
├── bin │ ├── air │ ├── govendor │ ├── swag │ └── wire ├── pkg │ ├── darwin_amd64 │ ├── mod │ └── sumdb └── src ├── calc ├── gin-blog ├── github.com ├── golang.org ├── google.golang.org ├── gopkg.in └── simplemath
This is not good for our specific projects. There is no Workspace concept to isolate each project, so I think the GOPATH directory should be public projects, such as open source dependent projects. During the development process, we will also download many dependencies. These dependencies are downloaded to this directory and mixed with our project files.
In addition, you can set the GOPATH of the project through the IDE, which is equivalent to adding a directory variable to the GOPATH during execution, that is, we create a project, and then there are three directories: bin, src and pkg, which are the same as GOPATH. In essence, the IDE actually sets the GOPATH when running:
GOPATH=/Users/fuxing/develop/testgo/calc-outside:/Users/fuxing/develop/go #gosetupWhen looking for variables, functions, class attributes and methods, Go language will first view the system environment variable GOPATH, and then Go to the src directory under the corresponding path according to the path list configured by the variable, and find the corresponding directory according to the package name. If the corresponding directory exists, then Go to the directory to find the corresponding variables, functions, class attributes and methods.
In fact, the official method of Go Modules is better.
1 Go Modules
From Go version 1.11, Go Modules management projects and dependencies are officially provided. From version 1.13, Go Modules support is enabled by default. The benefits of using Go Modules are obvious - you no longer need to rely on GOPATH. You can create Go projects anywhere. In China, you can configure the image source through GOPROXY to speed up the download of dependent packages. In other words, creating a project is a mod, which is basically what Go open source projects do at present. It's actually similar to Maven and Gradle.
// To create a mod project, you can also use the IDE to create a new mod project: go mod init calc-mod // Generally, the name of the open source project on github is like this; Unlike maven and gradle, the development does not need to be released to the warehouse! Just click tag after submitting the code go mod init github.com/fuxing-repo/fuxing-module-name // Create a module: to execute this command, there is one more go Mod file, which contains one line: module calc-mod // After import, execute the download dependency command without editing go Mod file. Dependency will be downloaded to GOPATH/pkg/mod directory go list
When you open different projects with GoLand, the dependent external libraries are displayed differently. If you create a project with GOPATH, you need to download the dependent package to GOPATH with the command:
go get -u github.com/fuxing-repo/fuxing-module-nameFour grammar
Package 1: package and Import
The package name in Java is usually very long, which corresponds to the folder name. It is used as a namespace. When introducing, you need to write a long string, or you can use wildcards:
The general package name in Go is the current folder name. The same package name can exist in the same project. If the same package name needs to be referenced at the same time, alias can be used to distinguish it, similar to JS. Generally, import is a package, unlike Java, which imports specific classes. There are different files in the same package, but the contents can be used without import. This is a bit similar to C's include. If there are multiple lines, wrap them in parentheses.
In the Go language, the visibility of variables, functions, class attributes and methods is associated with the package, not like Java. The visibility of class attributes and methods is encapsulated in the corresponding classes, and then their visibility is described by keywords such as private, protected and public. The Go language does not have these keywords, just like variables and functions, For custom classes in Go language, the visibility of attributes and methods is determined by their initial case. If the attribute name or method name is capitalized, these attributes and methods can be accessed directly in other packages, otherwise they can only be accessed in packages. Therefore, the visibility in Go language is package level, not class level.
In Java, only static or objects can use point operators, which are extremely common operations. In Go, you can also use a package name, which is used in combination with import. You can point out a function call, a structure and an interface. In addition, different from C, whether pointer address or object reference, point operator is used. There is no need to consider using point or arrow!
The package of the entry must be main, otherwise it can be compiled successfully, but it can't run:
Compiled binary cannot be executed.The reason is that we can't find the entry function. Like C and Java, we also need the main function.
2 variables
- Modify with var keyword (similar to JS). When there are multiple variables, wrap them in parentheses (). By default, they have initialization values, just like Java.
- If you assign a value during initialization, you don't need var to modify it. Unlike Java, the variable type is behind the variable rather than in front, but you need the: = symbol.
- The biggest change is that the type is behind the variable!
- The semicolon can be omitted in the statement;
var v1 int = 10 // Mode 1: routine initialization operation var v2 = 10 // In mode 2, the variable type will be automatically derived by the compiler v3 := 10 // In mode 3, var can be omitted, and the compiler can automatically deduce the type of v3 //java private HashMap<String, UGCUserDetail> mBlockInfo;
Multiple assignment
i, j = j, i
Variable exchange can be realized, which is a bit like JS object destructor, but it is actually different. With this capability, the function can return multiple values!
Anonymous variable
Use_ The function is to avoid creating and defining some meaningless variables, and not to allocate memory.
Pointer variable
Like C language, just recall the example of exchange value. What is the difference between value transmission and address transmission as parameters.
The reason why Go language introduces pointer type is mainly based on two considerations. One is to provide programmers with the ability to operate variables corresponding to memory data structures; The other is to improve the performance of the program (the pointer can directly point to the memory address of a variable value, which can greatly save memory space and have higher operation efficiency), which can not be ignored in system programming, operating system or network application.
Pointer has two usage scenarios in Go language: type pointer and array slicing.
As a type pointer, it is allowed to modify the data of this pointer type to point to other memory addresses. If a pointer is used to transfer data, there is no need to copy the data, so as to save memory space. In addition, unlike the pointer in C language, the type pointer in Go language cannot be offset and operated, so it is safer.
Variable type
Go language has built-in support for the following basic data types:
- Boolean type: bool
- Integer: int8, byte, int16, int, uint, uintptr, etc
- Floating point type: float32, float64
- Complex type: complex64, complex128
- string: string
- Character type: rune, essentially uint32
- Error type: error
In addition, the Go language supports the following composite types:
- pointer
- array
- slice
- Dictionary (map)
- Channel (chan)
- Structure (struct)
- interface
There is also const constant, iota, a predefined constant used to define enumeration. It can be considered as a constant that can be modified by the compiler. It is reset to 0 when each const keyword appears, and then before the next const, the number represented by iota will automatically increase by 1 every time it appears.
const ( Sunday = iota Monday Tuesday Wednesday Thursday Friday Saturday numberOfDays )
Type forced rotation
v1 := 99.99 v2 := int(v1) // v2 = 99 v1 := []byte{'h', 'e', 'l', 'l', 'o'} v2 := string(v1) // v2 = hello //The strconv package is generally used for character related conversion v1 := "100" v2, err := strconv.Atoi(v1) // Convert string to integer, v2 = 100 v3 := 100 v4 := strconv.Itoa(v3) // Convert integer to string, v4 = "100" //Structure type conversion //Type Asserts //x.(T) in fact, it is to judge whether T implements the X interface. If it does, concretize the X interface type into the T type; claims, ok := tokenClaims.Claims.(*jwt.StandardClaims)
Arrays and slices
//Define array var a [8]byte // An array of length 8, one byte per element var b [3][3]int // Two dimensional array (9 squares) var c [3][3][3]float64 // Three dimensional array (9 squares of three dimensions) var d = [3]int{1, 2, 3} // Initialize on declaration var e = new([3]string) // Initialize via new var f = make([]string, 3) // Initialize with make //initialization a := [5]int{1,2,3,4,5} b := [...]int{1, 2, 3} //section b := []int{} //Array slice is a variable length array c := a[1:3] // It is similar to subString or JS slice d := make([]int, 5) //make is equivalent to new and alloc, which are used to allocate memory //Length of array length := len(a) //Add an element b = append(b, 4)
Dictionaries
In fact, it is a map in Java. There are many differences in syntax.
var testMap map[string]int testMap = map[string]int{ "one": 1, "two": 2, "three": 3, } //You can also initialize as follows: var testMap = make(map[string]int) //map[string]int{} testMap["one"] = 1 testMap["two"] = 2 testMap["three"] = 3
make and new
// The make built-in function allocates and initializes an object of type // slice, map, or chan (only). Like new, the first argument is a type, not a // value. Unlike new, make's return type is the same as the type of its // argument, not a pointer to it. The specification of the result depends on // the type: // Slice: The size specifies the length. The capacity of the slice is // equal to its length. A second integer argument may be provided to // specify a different capacity; it must be no smaller than the // length. For example, make([]int, 0, 10) allocates an underlying array // of size 10 and returns a slice of length 0 and capacity 10 that is // backed by this underlying array. // Map: An empty map is allocated with enough space to hold the // specified number of elements. The size may be omitted, in which case // a small starting size is allocated. // Channel: The channel's buffer is initialized with the specified // buffer capacity. If zero, or the size is omitted, the channel is // unbuffered. func make(t Type, size ...IntegerType) Type // The new built-in function allocates memory. The first argument is a type, // not a value, and the value returned is a pointer to a newly // allocated zero value of that type. func new(Type) *Type
The difference is that the return value is different from the parameter. One is the value and the other is the pointer. slice, chan and map can only use make, which is the pointer itself. Other make and new are OK.
Magic nil
It's more comfortable to use null in Java. You can judge null directly. In addition to string type, you also need to judge the character as "". However, it's easier to judge null in Go. You can't judge nil, you can only judge "". However, nil in Go is different from null. In fact, it is very similar to = =, = = = in JS.
nil also has types.
func Foo() error { var err *os.PathError = nil // ... return err //The actual return is [nil, *os.PathError] //Return nil / / the correct way is to return nil directly. The actual return is [nil, nil] } func main() { err := Foo() fmt.Println(err) // <nil> fmt.Println(err == nil) // false fmt.Println(err == (*os.PathError)(nil)) //true }
Root Object: Object
In Java, if polymorphism is not used and there are no interfaces, parent classes or superclasses, Object is used as the root Object. In Go, if the function parameters do not know what type to use, interface {} is usually used. This is an empty interface, which represents any type, because it is not a weakly typed language, no any type, nor a strong Object-oriented language, and no Object, So this empty interface appears.
3 statement
A big feature is that you don't need parentheses.
control flow
The judgment conditions of if statements are not enclosed in parentheses. Variable initialization statements can also be written before them, which is similar to a for loop. The left curly bracket {must be on the same line as if or else.
The switch statement has become more powerful with these changes:
- The switch keyword can not be followed by variables, so the case must be followed by a conditional expression. In fact, it essentially beautifies if else if.
- If switch is followed by variables, case becomes powerful, and multiple result options can appear, separated by commas.
- swtich can also be followed by a function.
- There is no need to explicitly exit a case with break. If you want to penetrate the execution layer, you can use the fallthrough keyword.
score := 100 switch score { case 90, 100: fmt.Println("Grade: A") case 80: fmt.Println("Grade: B") case 70: fmt.Println("Grade: C") case 60: case 65: fmt.Println("Grade: D") default: fmt.Println("Grade: F") } s := "hello" switch { case s == "hello": fmt.Println("hello") fallthrough case s == "xxxx": fmt.Println("xxxx") case s != "world": fmt.Println("world") } //output: hello xxxx
Circulation process
The keywords while and repeat are removed, and only the keyword for is retained. In fact, it is almost used. There are still some keywords such as break and continue.
//General usage for i := 1; i <= 5; i++ { fmt.Println(i) } //Usage similar to while a := 1 for a <= 5 { fmt.Println(a) a ++ } //Dead cycle for { // do something } for ;; { // do something } //Usage similar to Java for each listArray := [...]string{"xiaobi", "xiaoda", "xiaoji"} for index, item := range listArray { fmt.Printf("hello, %d, %s\n", index, item) } //java for (String item : someList) { System.out.println(item); }
Jump process
Go magically retains the goto statement that has been abandoned. I remember that it is only Basic and Pascal. I don't know why.
i := 1 flag: for i <= 10 { if i%2 == 1 { i++ goto flag } fmt.Println(i) i++ }
The defer process is a bit like finally in Java, which ensures that it can be executed. I think the bottom layer is also the implementation of goto. Followed by a function call, you can delay the call of xxx function until the current function is executed.
This is the variable snapshot implementation of stack pressing.
func printName(name string) { fmt.Println(name) } func main() { name := "go" defer printName(name) // output: go name = "python" defer printName(name) // output: python name = "java" printName(name) // output: java } //output: java python go //Execute after defer on return var name string = "go" func myfunc() string { defer func() { name = "python" }() fmt.Printf("myfunc In function name: %s\n", name) return name } func main() { myname := myfunc() fmt.Printf("main In function name: %s\n", name) fmt.Println("main In function myname: ", myname) } //output: myfunc In function name: go main In function name: python main In function myname: go
4 function
- The keyword is function, but Java has no function keyword at all. Instead, it uses keywords such as public and void. JS can also use arrow functions to remove the function keyword.
- Curly braces for functions are mandatory at the end of the first line.
- Multiple values can be returned! The type of the return value is defined after the parameter instead of the function. Just like defining the variable, the type definition of the parameter is the same. If it is the same, the rightmost type will be retained and others will be omitted.
- You can explicitly declare the return value. If each return value must be explicit, you can omit the return variable.
//A return value func GetEventHandleMsg(code int) string { msg, ok := EventHandleMsgMaps[code] if ok { return msg } return "" } //Multiple return values func GetEventHandleMsg(code int) (string, error) { msg, ok := EventHandleMsgMaps[code] if ok { return msg, nil } return "", nil } //Do not explicitly return variable values func GetEventHandleMsg(code int) (msg string, e error) { var ok bool msg, ok = EventHandleMsgMaps[code] if ok { //do something return } return }
Anonymous functions and closures
The implementation in Java is generally internal classes and anonymous objects. Functions cannot be passed as parameters through methods. Only one object can be passed to implement the interface.
Go is as convenient as JS. You can pass functions and define anonymous functions.
//Pass anonymous function func main() { i := 10 add := func (a, b int) { fmt.Printf("Variable i from main func: %d\n", i) fmt.Printf("The sum of %d and %d is: %d\n", a, b, a+b) } callback(1, add); } func callback(x int, f func(int, int)) { f(x, 2) } //return anonymous function func main() { f := addfunc(1) fmt.Println(f(2)) } func addfunc(a int) func(b int) int { return func(b int) int { return a + b } }
Indefinite parameter
Similar to Java, the difference is that you also need to use To identify.
//definition func SkipHandler(c *gin.Context, skippers ...SkipperFunc) bool { for _, skipper := range skippers { if skipper(c) { return true } } return false } //call middlewares.SkipHandler(c, skippers...)
V. object oriented
The use of aliases is often used in C language. You can use the type class as an alias, which is very common, especially when looking at the source code:
type Integer intClass 1
There is no class definition. The classes in Go are defined by structures.
type Student struct { id uint name string male bool score float64 } //There is no constructor, but you can use functions to create instance objects, and you can specify field initialization, which is similar to the static factory method in Java func NewStudent(id uint, name string, male bool, score float64) *Student { return &Student{id, name, male, score} } func NewStudent2(id uint, name string, male bool, score float64) Student { return Student{id, name, male, score} }
2 member method
Defining the member function method of a class is implicit and the direction is opposite. It is not to declare which member methods the class has, but to declare which class the function belongs to. The declaration syntax is after the func keyword and before the function name. Be careful not to confuse the Java return value definition!
//This declaration is the same as C + +. This is not an ordinary function, but a member function. //Note that one of the two methods declares an address and the other declares a structure. Both of them can operate directly through points. func (s Student) GetName() string { return s.name } func (s *Student) SetName(name string) { s.name = name } //use func main() { //a is the pointer type a := NewStudent(1, "aa", false, 45) a.SetName("aaa") fmt.Printf("a name:%s\n", a.GetName()) b := NewStudent2(2, "bb", false, 55) b.SetName("bbb") fmt.Printf("b name:%s\n", b.GetName()) } //If the SetName method and GetName method belong to Student instead of * Student, the name modification will not succeed //In essence, declaring a member function is to pass an object, pointer, or reference in a place other than a function parameter, that is, to pass this pointer in a disguised form //That's why the case of unsuccessful name modification appears
3 succession
Without the extend keyword, there will be no inheritance, which can only be realized through combination. Composition solves the problem of multi inheritance, and the order of multi inheritance is different, and the memory structure is also different.
type Animal struct { name string } func (a Animal) FavorFood() string { return "FavorFood..." } func (a Animal) Call() string { return "Voice..." } type Dog struct { Animal } func (d Dog) Call() string { return "Woof, woof" } //In the second way, the address needs to be specified during initialization, and nothing else has changed type Dog2 struct { *Animal } func test() { d1 := Dog{} d1.name = "mydog" d2 := Dog2{} d2.name = "mydog2" //A structure is a value type. If a value variable is passed in, actually a copy of the structure value is passed in, which consumes more memory, //So the performance of the incoming pointer is better a := Animal{"ddog"} d3 := Dog{a} d4 := Dog2{&a} }
This syntax does not use member variables like the combination in Java, but directly refers to Animal without defining the variable name (of course, it is OK, but it is not necessary). Then you can access all properties and methods in Animal (if the two classes are not in the same package, you can only access the public properties and methods with uppercase letters in the parent class), You can also implement method rewriting.
4 interface
Java's interface is intrusive, which means that the implementation class must clearly declare that it implements an interface. The problem is that if the interface is changed, the implementation class must be changed, so there was always an abstract class in the middle.
//Define interface: type Phone interface { call() } //Implementation interface: type IPhone struct { name string } func (phone IPhone) call() { fmt.Println("Iphone calling.") }
Go's interface is non intrusive, because the implementation relationship between classes and interfaces is not explicitly declared, but judged by the system according to their method sets. A class must implement all methods of the interface to realize the interface. The inheritance between interfaces is the same as that of classes. Through combination implementation, the implementation logic of polymorphism is the same. If the method list of interface a is a subset of the method list of interface B, interface B can be assigned to interface a.
Six concurrent programming
At present, I haven't learned much about concurrent programming. I simply picked this classic producer consumer model example from the Internet to have a preliminary experience. I'll share it after further study.
// Data producer func producer(header string, channel chan<- string) { // Endless cycle, non-stop production data for { // Formats random numbers and strings as strings and sends them to the channel channel <- fmt.Sprintf("%s: %v", header, rand.Int31()) // Wait 1 second time.Sleep(time.Second) } } // Data consumer func customer(channel <-chan string) { // Keep getting data for { // Take data from the channel, where it will block until data is returned from the channel message := <-channel // print data fmt.Println(message) } } func main() { // Create a channel of type string channel := make(chan string) // Create concurrent goroutine for producer() function go producer("cat", channel) go producer("dog", channel) // Data consumption function customer(channel) } //output: dog: 1298498081 cat: 2019727887 cat: 1427131847 dog: 939984059 dog: 1474941318 cat: 911902081 cat: 140954425 dog: 336122540
VII. Summary
This is just a simple introduction. In fact, there are many things I haven't covered in Go, such as context, try catch, concurrency related (such as locks), Web development related and database related. Start with this post and continue to learn Go language sharing later.
Original link
This article is the original content of Alibaba cloud and cannot be reproduced without permission.