Go was invented by Ken Thompson, Rob Pike, and Robert Griesemer in 2007 and released in 2009. The main goal of Go is to “combine the development speed of dynamic languages such as Python with the performance and security of compiled languages such as C/C++”. It aims to reduce code complexity without compromising application performance and has the advantages of “simple deployment, good concurrency, good language design and good execution performance”.

The author | assign a line source | ali technology to the public

preface

I used to be a Developer based on Java language and did JavaWeb related development. Later, I switched to Android and still couldn’t leave Java until I switched to a big front-end. In fact, I have been writing business with JS. Now due to personal development reasons, came to Ali Cloud, due to the project needs to Go language; Years of programming experience told me that language is just a tool, the important thing is its ideas and logic, so only need to learn grammar, so I began to Go for three days, during which I mainly use Java and JS analogy, grammar changes, almost let me from the entry to give up! In fact, it is not really learning grammar, which contains a lot of Go design ideas. Just as the so-called good memory is better than typing the keyboard, learned things, or precipitation, can also be shared to discuss, more conducive to growth, so I simply recorded my Go language learning notes.

An introduction to the

Go was created by Ken Thompson, Rob Pike, and Robert Griesemer in 2007 and released in 2009. It was originally developed by Google and designed to meet Google’s needs. The main goal of Go is to “combine the development speed of dynamic languages such as Python with the performance and security of compiled languages such as C/C++”. It aims to reduce code complexity without compromising application performance and has the advantages of “simple deployment, good concurrency, good language design and good execution performance”. Most of all, it’s designed for concurrency, and concurrency is based on a Goroutine, which is like a thread, but not a thread, so you can think of a Goroutine as a virtual thread. The Go language runtime participates in scheduling goroutines and allocating goroutines to each CPU to maximize CPU performance.

The environment

Just as you need to download the JDK to play with Java, you need to download Go to develop with Go, which provides various Develop-Kits, libraries, and compilers. Download the MAC version PKG from the official website and install it directly. Run the go version command to verify the MAC version:

The MAC system is in the.bash_profile file:

export GOROOT=/usr/local/go
export GOPATH=$HOME/go
Copy the code
  • GOROOT: Represents the installation path for Go language compilation, tools, standard libraries, and so on, which is essentially the same as configuring JAVA_HOME.
  • GOPATH: This is a bit different from Java. There is no need to set this variable in Java. This represents the Go working directory. It is also common to set $GOPATH/bin 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 helloWorld directory and creating a hello.go file:

package main
import "fmt"
func main() {    
    fmt.Println("hello, world")
}
Copy the code

Go build hello.go to compile the hello file./hello; Or simply go run hello. You do not need to set environment variables to execute this command. It looks similar to C, but unlike Java, no virtual machine is required to run it. Early GO projects were also compiled using Makefiles. Later, powerful commands such as GO build and GO run were introduced to identify directories and files directly.

2 GoLand

Automatic import, super cool experience! Don’t press Command + /!

To run the project, you need to set the build config, similar to Android and Java, for example, to create a Hello-Goland project:

Check this when importing the Go Module project, otherwise you won’t be able to sync dependencies like Maven/Gradle:

3 VSCODE

Search directly for the Go plugin, the first one with the most installs, which I haven’t used yet so I’m not sure how.

Iii Engineering Structure

When setting GOPATH environment variables, there are three subdirectories: bin, PKG, and SRC, which are used to store executable files, package files, and source files respectively. When we run the Go command, if we specify something other than a file in the current directory or an absolute directory, we Go to the GOPATH directory to find it. After creating a directory for XXX in the GOPATH directory, you can run the go build xx command anywhere to build or run it.

The PKG directory should be the package files generated after go Install is executed, including. A files, which is equivalent to an archive.

├ ─ ─ bin │ ├ ─ ─ air │ ├ ─ ─ govendor │ ├ ─ ─ swag │ └ ─ ─ wire ├ ─ ─ PKG │ ├ ─ ─ darwin_amd64 │ ├ ─ ─ mod │ └ ─ ─ sumdb └ ─ ─ the SRC ├ ─ ─ calc ├ ─ ─ gin - blog ├ ─ ─ github.com ├ ─ ─ golang.org ├ ─ ─ google.golang.org ├ ─ ─ gopkg. In └ ─ ─ simplemathCopy the code

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 dependencies. We also download a lot of dependencies during development, and these dependencies are all downloaded into this directory and mixed up with our project files.

In addition, the IDE allows you to set the GOPATH of a project, which is equivalent to adding a directory variable to GOPATH at execution time. In other words, we create a project, and then there are three directories: bin, SRC, and PKG, just like GOPATH. When the IDE runs, it simply sets the GOPATH:

GOPATH=/Users/fuxing/develop/testgo/calc-outside:/Users/fuxing/develop/go #gosetup

The Go looking for a variable, function, class, attribute and method, the system will first check the GOPATH environment variables, and then according to the variable configuration list of paths, in turn, under the corresponding path to the SRC directory according to the package name to find the corresponding directory, if the corresponding directory exists, then to the directory to find the corresponding variable, function, class, properties and methods.

In fact, the official way to provide Go Modules is better.

1 Go Modules

Since Go 1.11, Go Modules management projects and dependencies have been officially provided. Since 1.13, support for Go Modules has been enabled by default. The benefits of using Go Modules are obvious — you don’t need to rely on GOPATH anymore. You can create Go projects anywhere, and in the country, you can configure the image source to speed up the download of dependencies through GOPROXY. In other words, creating a project is a mod, which is basically what all current Go open source projects do. Just like Maven and Gradle.

// To create a mod project, you can also use the IDE to new a mod project: go mod init calc-mod Unlike Maven and Gradle, you don't need to publish to a repository! Go mod init github.com/fuxing-repo/fuxing-module-name // Create a module: this command is executed with a go.mod file, which contains one line: Module calc-mod // import can be used to download dependencies without editing the go.mod file. Dependencies will be downloaded to the GOPATH/ PKG /mod directory Go ListCopy the code

Use GoLand to open different projects, the external libraries to display dependencies are different. If you create a project using GOPATH, you need to download the dependencies to GOPATH:

go get -u github.com/fuxing-repo/fuxing-module-name

Four grammar

1 Packages: Package and Import

In Java, the package name is usually long, which corresponds to the folder name. It is used as a namespace.

The general package name in Go is the name of the current folder. The same package name can exist in the same project. If the same package name needs to be referenced at the same time, it can be distinguished by alias, similar to JS. Typically, you import a package, not a concrete class as Java does. In the same package, different files, but the contents are available, do not need import. This is kind of like include in C. If there are multiple lines, wrap them in parentheses.

In Go, the visibility of variables, functions, and class attributes and methods is associated with the package, as opposed to Java, where the visibility of class attributes and methods is encapsulated in the corresponding class and described by the keywords private, protected, and public. The Go without these keywords, as well as variables and functions, custom class corresponding to the language, the visibility of properties and methods according to its first letter case to decide, if the property name or method name capitalize the first letter, you can direct access to the properties and methods in the other package, otherwise can only access inside the package, so the language is the visibility in the package level, Not class level.

In Java, only static, or objects can use dot operators, and that’s a very common operation, whereas in Go, you can also use a package name to dot, which is used in conjunction with import, you can point to a function call, you can point to a structure, an interface. In addition, unlike C, both pointer address, or object reference, all use the point operator, do not need to consider the use of points or arrows!

The package of the entry must be main, otherwise it will compile successfully, but it will not run:

Compiled binary cannot be executed.

The reason is that there is no entry function. Just like C and Java, you need a main function.

2 variables

  • Use the var keyword (similar to JS), enclose multiple variables in parentheses (), and initialize values by default, just like in Java.

  • If the value is assigned at initialization, you don’t need var. Unlike Java, the variable type comes after the variable, not before it, but with the := symbol.

  • The biggest change is that the type comes after the variable!

  • Statements can omit semicolons;

    Var v1 int = 10 var v2 = 10 v3 := 10 v3 := 10

    //java private HashMap<String, UGCUserDetail> mBlockInfo;

Multiple assignments

i, j = j, i
Copy the code

Variable exchange can be implemented, kind of like JS object destructor, but not the same. With this capability, functions can return multiple values!

Anonymous variable

The _ notation is used to avoid creating and defining meaningless variables and to avoid allocating memory.

Pointer to the variable

As with C, recall the example of swapping values, and what is the difference between passing a value and passing an address as an argument.

The reason why Go introduced pointer types is mainly based on two considerations. One is to provide programmers with the ability to manipulate the in-memory data structure corresponding to variables. The other is to improve the performance of the program (pointer can directly point to the memory address of a variable value, can greatly save memory space, operation efficiency is also higher), which can not be ignored in system programming, operating system or network applications.

Pointers are used in two scenarios in Go: type Pointers and array slicing.

When used as a type pointer, the data of this type pointer can be modified to point to other memory addresses. When passing data, if Pointers are used, data need not be copied, thus saving memory space. In addition, different from Pointers in C language, type Pointers in Go language cannot be offset and operated, so they are safer.

Variable types

The Go language has built-in support for these basic data types:

  • Boolean type: bool
  • Integer types: INT8, byte, INT16, int, uint, uintptr, etc
  • Floating-point types: float32 and float64
  • Complex type: complex64, complex128
  • String: string
  • The character type is rune, which is essentially a uint32
  • Error type: error

In addition, the Go language supports the following compound types:

  • Pointer
  • Array
  • Slice
  • Dictionary (MAP)
  • Channel (Chan)
  • Structure (struct)
  • Interface

And const constants, ioTA is a predefined constant that defines enumerations. Can be thought of as a constant that can be modified by the compiler, reset to 0 for each occurrence of a const keyword, and then automatically incremented by 1 for each occurrence of ioTA until the next occurrence of a const.

const (
    Sunday = iota 
    Monday 
    Tuesday 
    Wednesday 
    Thursday 
    Friday 
    Saturday 
    numberOfDays
)
Copy the code

Strong type turn

V1, v2 = 99.99: int = (v1) / / v1 v2 = 99: = byte [] {' h ', 'e', 'l', 'l', V1 := "100" v2, err := strconv.atoi (v1) // Convert string to integer, V3 := 100 v4 := strconv.itoa (v3) // convert integer to string, v4 = "100" // type predicate //x.(T) Specify the interface type X to type T; claims, ok := tokenClaims.Claims.(*jwt.StandardClaims)Copy the code

Arrays and slices

Var a [8]byte // Array of length 8, Var c [3][3][3]float64 var d = [3]int{1, 2, Var e = new([3]string) var f = make([]string, 3) initialization through the make / / / / initializes a: = [5] int {1, 2, 3, 4, 5} : b = [...]. Int {1, 2, 3} // slice b := []int{} // slice c := a[1:3] // sort of like subString, Js. slice d := make([]int, 5) //make = new, alloc, to allocate memory // length := len(a) // add an element b = append(b, 4)Copy the code

The dictionary

In fact, map in Java, there are many different syntax.

var testMap map[string]int testMap = map[string]int{ "one": 1, "two": 2, "three": } // We can also initialize it like this:  var testMap = make(map[string]int) //map[string]int{} testMap["one"] = 1 testMap["two"] = 2 testMap["three"] = 3Copy the code

The 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) *TypeCopy the code

Slice, chan, and map can only use make, which are Pointers themselves. Make, new will do.

The magic of nil

In Java, it’s nice to use null, so it’s null, except for strings, and it’s null, but in Go it’s a little easier to use null, you can’t use nil, you can only use “”. Go inside of nil, however, and null is not the same, is actually and JS = =, = = =.

Nil is also typed.

Func Foo() error {var err * os.patherror = nil //... Return err // returns [nil, * os.patherror] // Return nil // The correct way to return nil is to return nil. nil] } func main() { err := Foo() fmt.Println(err) // <nil> fmt.Println(err == nil) // false fmt.Println(err == (*os.PathError)(nil)) //true }Copy the code

Root Object: Object

In Java, if you don’t have polymorphism, if you don’t have an interface, if you don’t have a parent class, if you don’t have a superclass, you use Object as the root Object. In Go, if you don’t know what type to use for a function parameter, you usually use interface{}, which is an empty interface, which means any type, because it’s not a weakly typed language, there’s no any type, It’s not a strong object-oriented language, there’s no Object, so you have this empty interface.

3 statements

One of the big features is that you don’t have to use parentheses anywhere.

Control process

If statements have no parentheses around them. They can also be preceded by variable initializers, similar to for loops, where the open curly brace {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 a variable, so that case must be followed by a conditional expression, in essence, if-else-if.

  • Case also becomes powerful if the switch is followed by a variable, allowing multiple result options to appear, separated by commas.

  • Swtich can also be followed by a function.

  • There is no need to use break to exit a case explicitly, but the fallthrough keyword can be used to execute through a level.

    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 ! 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 the same. Break, continue, there are some keywords.

// for I := 1; i <= 5; I ++ {fmt.println (I)} // while a := 1 for a <= 5 {fmt.println (a) a ++} // loop for {// do something} for; {// do something} // 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); }Copy the code

Jump processes

Go miraculously retains the abandoned GOto statement, which was only used in Basic, Pascal and other languages.

i := 1
flag:
for i <= 10 {
    if i%2 == 1 {
        i++
        goto flag
    }
    fmt.Println(i)
    i++
}
Copy the code

The defer process is a bit like the Finally in Java that guarantees execution, and I feel like the underlying implementation of Goto is also there. Following a function call, it is possible to postpone the XXX function call until the current function has finished executing.

This is the variable snapshot implementation of the pushdown.

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: Var name string = "go" func myfunc() string {defer func() {name = "python"}() In FMT. Printf (" myfunc function name: % s \ n ", name) return the name} func main () {myname: = myfunc (FMT). The Printf (" in the name of the main function: %s\n", name) FMT.Println(" myname: ", myname)} //output: myfunc: go main: name: Myname: go in python mainCopy the code

4 function

  • The keyword is func, whereas Java does not use the function keyword at all, using public, void, etc. JS can also use arrow functions to remove the function keyword.

  • Function curly braces are mandatory at the end of the first line.

  • Multiple values can be returned! The type definition of the return value comes after the parameter, instead of being written at the beginning of the function definition. As with variables, the type definition of the parameter comes later. If they are the same, the right-most type is kept and the rest is omitted.

  • The return value can be explicitly declared. Each return value must be explicit to omit the return variable.

    Func GetEventHandleMsg(code int) string {MSG, Func GetEventHandleMsg(code int) (string, error) { msg, ok := EventHandleMsgMaps[code] if ok { return msg, nil } return “”, 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

In Java, the implementation is generally an internal class, anonymous objects, can not pass functions as parameters through methods, can only pass an object, implementation interface.

Go is just as convenient as JS, passing functions and defining anonymous functions.

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, Func main() {f := addFunc (1) fmt.println (f(2))} func addfunc(a int) func(b int) int {return func(b int)  int) int { return a + b } }Copy the code

Uncertain parameters

Similar to Java, except that the call also needs to use… To identify.

// define func SkipHandler(c *gin.Context, skippers... SkipperFunc) bool { for _, Skipper := range skipper {if skipper(c) {return true}} return false} // Middlewares.skiphandler (c, skippers...)Copy the code

Five object oriented

In C language often useful to the use of alias, you can use the type class to create an alias, is very common, especially when looking at the source code often appear:

type Integer int

Class 1

There is no class definition; classes in Go are defined in structs.

Type Student struct {id uint name string male bool score float64} 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} }Copy the code

2 Member methods

The member function methods of a class are implicit, in the opposite direction. Instead of declaring which member methods the class has, we declare which class the function belongs to. Declaration syntax is after the func keyword, before the function name, be careful not to confuse the Java return value definition!

// this declaration is the same as C++, this is not a normal function, but a member function. // Two methods declare the address and the structure, both of which can be operated directly through the point. Func (s Student) GetName() string {return s.name} func (s *Student) SetName(name string) {s.name = name} // Use func Main () {//a is a pointer type a := NewStudent(1, "aa", false, 45) a.setName ("aaa") ftt.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 and GetName methods belong to Student instead of *Student, then the name will not be changed. That is, passing the this pointer // will result in an unsuccessful case of changing the nameCopy the code

3 inheritance

Without the extend keyword, there would be no inheritance, only composition. Composition solves the problem of multiple inheritance, and the order of multiple inheritance is different, and the memory structure is 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 "Dog"} Type Dog2 struct {*Animal} func test() {d1 := Dog{} d1.name = "mydog" d2 := Dog2{} d2.name = "mydog2" A := Animal{"ddog"} d3 := Dog{a} d4 := Dog2{&a}}Copy the code

Instead of using a combination of member variables like in Java, this syntax refers directly to Animal and does not specify a variable name (it is possible, but not necessary), and then accesses all properties and methods in Animal (if two classes are not in the same package, Only public properties and methods in the parent class can be accessed with capital letters), and method overrides can be implemented.

4 interface

Java interfaces are intrusive, meaning that implementation classes must explicitly declare that they implement an interface. The problem is that if the interface is changed, the implementation class has to be changed, so there was always an abstract class in the middle.

Type Phone interface {call()}  type IPhone struct { name string } func (phone IPhone) call() { fmt.Println("Iphone calling.") }Copy the code

Go’s interface is non-intrusive, because the relationship between classes and interfaces is not explicitly declared, but is determined by the system based on their set of methods. To implement an interface, a class must implement all the methods of the interface. Inheritance between interfaces is the same as inheritance between classes. The implementation logic of polymorphism is the same. If the list of methods of interface A is A subset of the list of methods of interface B, then interface B can be assigned to interface A.

Vi Concurrent programming

At present, I haven’t learned much about concurrent programming, so I simply picked this classic example of producer consumer model from the Internet to have a preliminary feeling, and then I will share it after further study.

// func producer(header string, channel chan< -string) { For {// format random numbers and strings as strings and send them to channel < -fmt.sprintf ("%s: %v", header, Rd.int31 ()) // wait 1 Second time.sleep (time.second)}} // Data consumer func customer(channel <-chan string) {// Keep getting data for {// Fetching data from the channel, Println(message)}} func main() {// Create a string channel channel := make(chan) Goroutine go producer("cat", channel) Go producer("dog", Customer (channel)} //output: dog: 1298498081 cat: 2019727887 cat: 1427131847 dog: 939984059 dog: 1474941318 cat: 911902081 cat: 140954425 dog: 336122540Copy the code

Seven summarizes

This is just a quick primer, but there are a lot of things I haven’t covered in Go, such as context, try-catch, concurrency (locks, etc.), Web development, database. Start with this post and continue to learn Go language sharing.

The original link

This article is the original content of Aliyun and shall not be reproduced without permission.