围棋学习软件

Let’s start with a small introduction to Go (or Golang). Go was designed by Google engineers Robert Griesemer, Rob Pike, and Ken Thompson. It is a statically typed, compiled language. The first version was released as open source in March 2012.

让我们从Go(或Golang)的简短介绍开始。 Go是由Google工程师Robert Griesemer,Rob Pike和Ken Thompson设计的。 它是一种静态类型的编译语言。 第一个版本于2012年3月作为开源发布。

“Go is an open source programming language that makes it easy to build simple, reliable, and efficient software”. — GoLang

“ Go是一种开放源代码编程语言,可轻松构建简单,可靠且高效的软件”。 — GoLang

In many languages, there are many ways to solve a given problem. Programmers can spend a lot of time thinking about the best way to solve it.

在许多语言中,有许多方法可以解决给定的问题。 程序员可能会花费大量时间来思考解决问题的最佳方法。

Go, on the other hand, believes in fewer features — with only one right way to solve the problem.

另一方面,Go相信更少的功能-只有一种解决问题的正确方法。

This saves developers time and makes the large codebase easy to maintain. There are no “expressive” features like maps and filters in Go.

这样可以节省开发人员时间,并使大型代码库易于维护。 Go中没有诸如地图和过滤器之类的“表达性”功能。

“When you have features that add expressiveness it typically adds expense” — Rob Pike

“当您具有增加表达力的功能时,通常会增加费用” – Rob Pike

入门 (Getting Started)

Go is made of packages. The package main tells the Go compiler that the program is compiled as an executable, rather than a shared library. It is the entry point for an application. The main package is defined as:

Go由包组成。 包主体告诉Go编译器该程序被编译为可执行文件,而不是共享库。 它是应用程序的入口点。 主程序包定义为:

package main

Let’s move ahead by writing a simple hello world example by creating a file main.go in the Go workspace.

让我们通过在Go工作区中创建一个文件main.go来编写一个简单的hello world示例。

工作空间 (Workspace)

A workspace in Go is defined by the environment variable GOPATH.

Go中的工作空间由环境变量定义 GOPATH

Any code you write is to be written inside the workspace. Go will search for any packages inside the GOPATH directory, or the GOROOT directory, which is set by default when installing Go. GOROOT is the path where the go is installed.

您编写的任何代码均应写入工作空间内。 Go将搜索GOPATH目录或GOROOT目录(安装Go时默认设置)内的所有软件包。 GOROOT 是go安装的路径。

Set GOPATH to your desired directory. For now, let’s add it inside a folder ~/workspace.

GOPATH设置为所需的目录。 现在,让我们将其添加到文件夹~/workspace

# export env
export GOPATH=~/workspace
# go inside the workspace directory
cd ~/workspace

Create the file main.go with the following code inside the workspace folder we just created.

在我们刚刚创建的工作空间文件夹中,使用以下代码创建文件main.go

你好,世界! (Hello World!)

package mainimport ("fmt"
)func main(){fmt.Println("Hello World!")
}

In the above example, fmt is a built-in package in Go which implements functions for formatting I/O.

在上面的示例中, fmt是Go中的内置程序包,它实现用于格式化I / O的功能。

We import a package in Go by using the import keyword. func main is the main entry point where the code gets executed. Println is a function inside the package fmt which prints “hello world” for us.

我们通过使用import在Go中导入一个包 关键词。 func main是执行代码的主要入口点。 Printlnfmt软件包中的一个函数,为我们打印“ hello world”。

Let’s see by running this file. There are two ways we can run a Go command. As we know, Go is a compiled language, so we first need to compile it before executing.

让我们通过运行该文件来看看。 我们可以通过两种方式运行Go命令。 众所周知,Go是一种编译语言,因此在执行之前我们首先需要对其进行编译。

> go build main.go

This creates a binary executable file main which now we can run:

这将创建一个二进制可执行文件main ,现在我们可以运行它:

> ./main
# Hello World!

There is another, simpler, way to run the program. The go run command helps abstract the compilation step. You can simply run the following command to execute the program.

还有另一种更简单的方法来运行程序。 go run命令有助于抽象编译步骤。 您只需运行以下命令即可执行该程序。

go run main.go
# Hello World!

Note: To try out the code that is mentioned in this blog you can use https://play.golang.org

注意 :要试用此博客中提到的代码,可以使用https://play.golang.org

变数 (Variables)

Variables in Go are declared explicitly. Go is a statically typed language. This means that the variable type is checked at the time of variable declaration. A variable can be declared as:

Go中的变量被明确声明。 Go是一种静态类型的语言。 这意味着在变量声明时检查变量类型。 变量可以声明为:

var a int

In this case, the value will be set as 0. Use the following syntax to declare and initialize a variable with a different value:

在这种情况下,该值将设置为0。使用以下语法声明和初始化具有不同值的变量:

var a = 1

Here the variable is automatically assigned as an int. We can use a shorthand definition for the variable declaration as:

此处,变量自动分配为int。 我们可以为变量声明使用简写定义:

message := "hello world"

We can also declare multiple variables in the same line:

我们还可以在同一行中声明多个变量:

var b, c int = 2, 3

资料类型 (Data types)

Like any other programming language, Go supports various different data structures. Let’s explore some of them:

像任何其他编程语言一样,Go支持各种不同的数据结构。 让我们探索其中的一些:

数字,字符串和布尔值 (Number, String, and Boolean)

Some of the supported number store types are int, int8, int16, int32, int64,uint, uint8, uint16, uint32, uint64, uintptr…

一些受支持 数字存储类型为int,int8,int16,int32,int64,uint,uint8,uint16,uint32,uint64,uintptr…

The string type stores a sequence of bytes. It is represented and declared with keyword string.

字符串类型存储字节序列。 它用关键字string表示和声明。

A boolean value is stored using the keyword bool.

一个 布尔值 使用关键字bool存储bool

Go also supports complex number type data types, which can be declared with complex64 and complex128.

Go还支持复数类型数据类型,可以使用complex64complex128进行声明。

var a bool = true
var b int = 1
var c string = 'hello world'
var d float32 = 1.222
var x complex128 = cmplx.Sqrt(-5 + 12i)

数组,切片和贴图 (Arrays, Slices, and Maps)

An array is a sequence of elements of the same data type. Arrays have a fixed length defined at declaration, so it cannot be expanded more than that. An array is declared as:

数组是具有相同数据类型的元素序列。 数组在声明时定义了固定的长度,因此不能扩展超过该长度。 数组声明为:

var a [5]int

Arrays can also be multidimensional. We can simply create them with the following format:

数组也可以是多维的。 我们可以简单地使用以下格式创建它们:

var multiD [2][3]int

Arrays are limiting for cases when the values of array changes in runtime. Arrays also do not provide the ability to get a subarray. For this, Go has a data type called slices.

对于运行时数组值更改的情况,数组是有限制的。 数组也不提供获取子数组的能力。 为此,Go具有称为切片的数据类型。

Slices store a sequence of elements and can be expanded at any time. Slice declaration is similar to array declaration — without the capacity defined:

切片存储一系列元素,并且可以随时扩展。 切片声明类似于数组声明-未定义容量:

var b []int

This creates a slice with zero capacity and zero length. Slices can also be defined with capacity and length. We can use the following syntax for it:

这将创建零容量和零长度的切片。 也可以使用容量和长度来定义切片。 我们可以使用以下语法:

numbers := make([]int,5,10)

Here, the slice has an initial length of 5 and has a capacity of 10.

在这里,切片的初始长度为5,容量为10。

Slices are an abstraction to an array. Slices use an array as an underlying structure. A slice contains three components: capacity, length, and a pointer to the underlying array as shown in the diagram below:

切片是对数组的抽象。 切片使用数组作为基础结构。 切片包含三个部分:容量,长度和指向基础数组的指针,如下图所示:

The capacity of a slice can be increased by using the append or a copy function. An append function adds value to the end of the array and also increases the capacity if needed.

可以通过使用附加或复制功能来增加切片的容量。 附加函数将值添加到数组的末尾,并在需要时增加容量。

numbers = append(numbers, 1, 2, 3, 4)

Another way to increase the capacity of a slice is to use the copy function. Simply create another slice with a larger capacity and copy the original slice to the newly created slice:

增加切片容量的另一种方法是使用副本 功能。 只需创建另一个更大容量的切片,然后将原始切片复制到新创建的切片中:

// create a new slice
number2 := make([]int, 15)
// copy the original slice to new slice
copy(number2, number)

We can create a sub-slice of a slice. This can be done simply using the following command:

我们可以创建切片的子切片。 只需使用以下命令即可完成此操作:

// initialize a slice with 4 len and values
number2 = []int{1,2,3,4}
fmt.Println(numbers) // -> [1 2 3 4]
// create sub slices
slice1 := number2[2:]
fmt.Println(slice1) // -> [3 4]
slice2 := number2[:3]
fmt.Println(slice2) // -> [1 2 3]
slice3 := number2[1:4]
fmt.Println(slice3) // -> [2 3 4]

Maps are a data type in Go, which maps keys to values. We can define a map using the following command:

映射是Go中的一种数据类型,它将键映射到值。 我们可以使用以下命令定义地图:

var m map[string]int

Here m is the new map variable, which has its keys as string and values are integers. We can add keys and values easily to a map:

这里m是新的map变量,它的键为string ,值是integers 。 我们可以轻松地向地图添加键和值:

// adding key/value
m['clearity'] = 2
m['simplicity'] = 3
// printing the values
fmt.Println(m['clearity']) // -> 2
fmt.Println(m['simplicity']) // -> 3

类型转换 (Typecasting)

One type of data type can be converted into another using type casting. Let’s see a simple type conversion:

可以使用类型转换将一种类型的数据类型转换为另一种类型。 让我们看一个简单的类型转换:

a := 1.1
b := int(a)
fmt.Println(b)
//-> 1

Not all types of data type can be converted to another type. Make sure that the data type is compatible with the conversion.

并非所有类型的数据类型都可以转换为另一种类型。 确保数据类型与转换兼容。

条件语句 (Conditional Statements)

如果别的 (if else)

For conditional statements, we can use if-else statements as shown in the example below. Make sure that the curly braces are in the same line as the condition is.

对于条件语句,我们可以使用if-else语句,如下例所示。 确保花括号与条件在同一行。

if num := 9; num < 0 {fmt.Println(num, "is negative")
} else if num < 10 {fmt.Println(num, "has 1 digit")
} else {fmt.Println(num, "has multiple digits")
}

开关盒 (switch case)

Switch cases helps organize multiple condition statements. The following example shows a simple switch case statement:

切换案例有助于组织多个条件语句。 以下示例显示了一个简单的switch case语句:

i := 2
switch i {
case 1:fmt.Println("one")
case 2:fmt.Println("two")
default:fmt.Println("none")
}

循环播放 (Looping)

Go has a single keyword for the loop. A sngle for loop command help achieve different kinds of loops:

Go具有用于循环的单个关键字。 sngle for loop命令可帮助实现各种循环:

i := 0
sum := 0
for i < 10 {sum += 1i++
}
fmt.Println(sum)

The above example is similar to a while loop in C. The same for statement can be used for a normal for loop:

上面的示例类似于C中的while循环。相同的for语句可用于普通的for循环:

sum := 0
for i := 0; i < 10; i++ {sum += i
}
fmt.Println(sum)

Infinite loop in Go:

Go中的无限循环:

for {
}

指针 (Pointers)

Go provides pointers. Pointers are the place to hold the address of a value. A pointer is defined by *. A pointer is defined according to the type of data. Example:

Go提供了指针。 指针是保存值地址的地方。 指针由*定义。 根据数据类型定义一个指针。 例:

var ap *int

Here ap is the pointer to an integer type. The & operator can be used to get the address of a variable.

ap是指向整数类型的指针。 &运算符可用于获取变量的地址。

a := 12
ap = &a

The value pointed by the pointer can be accessed using the * operator:

指针指向的值可以使用*运算符进行访问:

fmt.Println(*ap)
// => 12

Pointers are usually preferred while passing a struct as an argument or while declaring a method for a defined type.

在将结构作为参数传递或为定义的类型声明方法时,通常首选指针。

  1. While passing value the value is actually copied which means more memory传递值时,实际上会复制该值,这意味着需要更多内存
  2. With the pointer passed, the value changed by the function is reflected back in the method/function caller.传递指针后,函数更改的值会在方法/函数调用器中反映出来。

Example:

例:

func increment(i *int) {*i++
}
func main() {i := 10increment(&i)fmt.Println(i)
}
//=> 11

Note: While you are trying out the example code in the blog, do not forget to include it with package main and import fmt or other packages when needed as shown in the first main.go example above.

注意:在博客中尝试示例代码时,请不要忘记将其包含在main软件包中,并在需要时导入fmt或其他软件包,如上面的第一个main.go示例所示。

功能 (Functions)

The main function defined in the main package is the entry point for a go program to execute. More functions can be defined and used. Let’s look into a simple example:

在主程序包中定义的主要功能是执行go程序的入口。 可以定义和使用更多功能。 让我们看一个简单的例子:

func add(a int, b int) int {c := a + breturn c
}
func main() {fmt.Println(add(2, 1))
}
//=> 3

As we can see in the above example, a Go function is defined using the func keyword followed by the function name. The arguments a function takes needs to be defined according to its data type, and finally the data type of the return.

如上例所示,使用func关键字后跟函数名称定义了Go函数。 需要根据函数的数据类型定义函数的自变量 ,最后根据返回值的数据类型进行定义。

The return of a function can be predefined in function as well:

函数的返回也可以在函数中预定义:

func add(a int, b int) (c int) {c = a + breturn
}
func main() {fmt.Println(add(2, 1))
}
//=> 3

Here c is defined as the return variable. So the variable c defined would be automatically returned without needing to be defined at the return statement at the end.

这里c被定义为返回变量。 因此,定义的变量c将自动返回,而无需在最后的return语句中定义。

You can also return multiple return values from a single function separating return values with a comma.

您还可以从单个函数中返回多个返回值,这些函数用逗号分隔返回值。

func add(a int, b int) (int, string) {c := a + breturn c, "successfully added"
}
func main() {sum, message := add(2, 1)fmt.Println(message)fmt.Println(sum)
}

方法,结构和接口 (Method, Structs, and Interfaces)

Go is not a completely object-oriented language, but with structs, interfaces, and methods it has a lot of object-oriented support and feel.

Go不是一种完全面向对象的语言,但是具有结构,接口和方法,它具有很多面向对象的支持和感觉。

结构 (Struct)

A struct is a typed, collection of different fields. A struct is used to group data together. For example, if we want to group data of a Person type, we define a person’s attribute which could include name, age, gender. A struct can be defined using the following syntax:

结构是不同字段的类型化集合。 结构用于将数据分组在一起。 例如,如果要对“人”类型的数据进行分组,则定义一个人的属性,其中可以包括姓名,年龄,性别。 可以使用以下语法定义结构:

type person struct {name stringage intgender string
}

With a person type struct defined, now let’s create a person:

定义了人员类型结构后,现在让我们创建一个人员:

//way 1: specifying attribute and value
p = person{name: "Bob", age: 42, gender: "Male"}
//way 2: specifying only value
person{"Bob", 42, "Male"}

We can easily access these data with a dot(.)

我们可以使用点(。)轻松访问这些数据。

p.name
//=> Bob
p.age
//=> 42
p.gender
//=> Male

You can also access attributes of a struct directly with its pointer:

您还可以直接使用其指针访问结构的属性:

pp = &person{name: "Bob", age: 42, gender: "Male"}
pp.name
//=> Bob

方法 (Methods)

Methods are a special type of function with a receiver. A receiver can be both a value or a pointer. Let’s create a method called describe which has a receiver type person we created in the above example:

方法是带有接收器的一种特殊功能 接收者可以是值或指针。 让我们创建一个名为describe的方法,该方法具有在上面的示例中创建的接收者类型的人员:

package main
import "fmt"// struct defination
type person struct {name   stringage    intgender string
}// method defination
func (p *person) describe() {fmt.Printf("%v is %v years old.", p.name, p.age)
}
func (p *person) setAge(age int) {p.age = age
}func (p person) setName(name string) {p.name = name
}func main() {pp := &person{name: "Bob", age: 42, gender: "Male"}pp.describe()// => Bob is 42 years oldpp.setAge(45)fmt.Println(pp.age)//=> 45pp.setName("Hari")fmt.Println(pp.name)//=> Bob
}

As we can see in the above example, the method now can be called using a dot operator as pp.describe. Note that the receiver is a pointer. With the pointer we are passing a reference to the value, so if we make any changes in the method it will be reflected in the receiver pp. It also does not create a new copy of the object, which saves memory.

如上例所示,现在可以使用点运算符pp.describe调用该方法。 注意,接收者是一个指针。 通过指针,我们传递了对该值的引用,因此,如果对方法进行任何更改,它将反映在接收器pp中。它也不会创建该对象的新副本,从而节省了内存。

Note that in the above example the value of age is changed, whereas the value of name is not changed because the method setName is of the receiver type whereas setAge is of type pointer.

请注意,在上面的示例中,age的值已更改,而name的值未更改,因为方法setName是接收者类型,而setAge是指针类型。

介面 (Interfaces)

Go interfaces are a collection of methods. Interfaces help group together the properties of a type. Let’s take the example of an interface animal:

Go接口是方法的集合。 接口可将类型的属性组合在一起。 让我们以接口动物为例:

type animal interface {description() string
}

Here animal is an interface type. Now let’s create 2 different type of animals which implement the animal interface type:

这里的动物是接口类型。 现在,让我们创建两种不同类型的动物,它们实现动物接口类型:

package mainimport ("fmt"
)type animal interface {description() string
}type cat struct {Type  stringSound string
}type snake struct {Type      stringPoisonous bool
}func (s snake) description() string {return fmt.Sprintf("Poisonous: %v", s.Poisonous)
}func (c cat) description() string {return fmt.Sprintf("Sound: %v", c.Sound)
}func main() {var a animala = snake{Poisonous: true}fmt.Println(a.description())a = cat{Sound: "Meow!!!"}fmt.Println(a.description())
}//=> Poisonous: true
//=> Sound: Meow!!!

In the main function, we create a variable a of type animal. We assign a snake and a cat type to the animal and use Println to print a.description. Since we have implemented the method describe in both of the types (cat and snake) in a different way we get the description of the animal printed.

在main函数中,我们创建一个animal类型的变量a 。 我们为动物指定蛇和猫的类型,并使用Println打印说明。 由于我们以不同的方式实现了在两种类型(猫和蛇)中描述的方法,因此我们获得了对动物的描述。

配套 (Packages)

We write all code in Go in a package. The main package is the entry point for the program execution. There are lots of built-in packages in Go. The most famous one we have been using is the fmt package.

我们将所有代码都封装在Go中。 主程序包是程序执行的入口点。 Go中有很多内置软件包。 我们一直使用的最著名的是fmt软件包。

“Go packages in the main mechanism for programming in the large that go provides and they make possible to divvy up a large project into smaller pieces.”

“ go软件包提供了大型编程的主要机制中的Go软件包,它们使将大型项目分成较小的部分成为可能。”

— Robert Griesemer

—罗伯特·格里塞默尔

安装套件 (Installing a package)

go get <package-url-github>
// example
go get github.com/satori/go.uuid

The packages we installed are saved inside the GOPATH env which is our work directory. You can see the packages by going inside the pkg folder inside our work directory cd $GOPATH/pkg.

我们安装的软件包保存在我们的工作目录GOPATH env中。 您可以通过进入工作目录cd $GOPATH/pkg的pkg文件夹查看软件包。

创建一个自定义包 (Creating a custom package)

Let’s start by creating a folder custom_package:

让我们从创建一个文件夹custom_package开始:

> mkdir custom_package
> cd custom_package

To create a custom package we need to first create a folder with the package name we need. Let’s say we are building a package person. For that let’s create a folder named person inside custom_package folder:

要创建自定义程序包,我们需要首先创建一个具有所需程序包名称的文件夹。 假设我们正在建立一个打包person 。 为此,我们在custom_package文件夹中创建一个名为person文件夹:

> mkdir person
> cd person

Now let’s create a file person.go inside this folder.

现在,让我们在此文件夹中创建一个文件person.go。

package person
func Description(name string) string {return "The person name is: " + name
}
func secretName(name string) string {return "Do not share"
}

We now need to install the package so that it can be imported and used. So let’s install it:

现在,我们需要安装该软件包,以便可以导入和使用它。 因此,让我们安装它:

> go install

Now let’s go back to the custom_package folder and create a main.go file

现在让我们回到custom_package文件夹并创建一个main.go文件

package main
import("custom_package/person""fmt"
)
func main(){ p := person.Description("Milap")fmt.Println(p)
}
// => The person name is: Milap

Here we can now import the package person we created and use the function Description. Note that the function secretName we created in the package will not be accessible. In Go, the method name starting without a capital letter will be private.

现在,我们可以在这里导入创建的包person并使用功能描述。 请注意,我们在包中创建的函数secretName将无法访问。 在Go中,以大写字母开头的方法名称将是私有的。

包文件 (Packages Documentation)

Go has built-in support for documentation for packages. Run the following command to generate documentation:

Go内置了对软件包文档的支持。 运行以下命令以生成文档:

godoc person Description

This will generate documentation for the Description function inside our package person. To see the documentation run a web server using the following command:

这将为我们的打包人员生成Description函数的文档。 要查看文档,请使用以下命令运行Web服务器:

godoc -http=":8080"

Now go to the URL http://localhost:8080/pkg/ and see the documentation of the package we just created.

现在转到URL http:// localhost:8080 / pkg /并查看我们刚刚创建的软件包的文档。

Go中的一些内置软件包 (Some built-in packages in Go)

fmt

fmt

The package implements formatted I/O functions. We have already used the package for printing out to stdout.

该程序包实现格式化的I / O功能。 我们已经使用该软件包将其打印输出到stdout。

json

json

Another useful package in Go is the json package. This helps to encode/decode the JSON. Let’s take an example to encode/decode some json:

Go中另一个有用的软件包是json软件包。 这有助于对JSON进行编码/解码。 让我们以一个示例来对一些json进行编码/解码:

Encode

编码

package mainimport ("fmt""encoding/json"
)func main(){mapA := map[string]int{"apple": 5, "lettuce": 7}mapB, _ := json.Marshal(mapA)fmt.Println(string(mapB))
}

Decode

解码

package mainimport ("fmt""encoding/json"
)type response struct {PageNumber int `json:"page"`Fruits []string `json:"fruits"`
}func main(){str := `{"page": 1, "fruits": ["apple", "peach"]}`res := response{}json.Unmarshal([]byte(str), &res)fmt.Println(res.PageNumber)
}
//=> 1

While decoding the json byte using unmarshal, the first argument is the json byte and the second argument is the address of the response type struct where we want the json to be mapped to. Note that the json:”page” maps page key to PageNumber key in the struct.

当使用unmarshal解码json字节时,第一个参数是json字节,第二个参数是我们希望将json映射到的响应类型struct的地址。 请注意, json:”page”将页面密钥映射到结构中的PageNumber密钥。

错误处理 (Error Handling)

Errors are the undesired and unexpected result of a program. Let’s say we are making an API call to an external service. This API call may be successful or could fail. An error in a Go program can be recognized when an error type is present. Let’s see the example:

错误是程序的意外结果。 假设我们正在对外部服务进行API调用。 此API调用可能成功或失败。 存在错误类型时,可以识别Go程序中的错误。 让我们来看一个例子:

resp, err := http.Get("http://example.com/")

Here the API call to the error object may pass or could fail. We can check if the error is nil or present and handle the response accordingly:

在这里,对错误对象的API调用可能通过或失败。 我们可以检查错误是否为nil或存在,并相应地处理响应:

package mainimport ("fmt""net/http"
)func main(){resp, err := http.Get("http://example.com/")if err != nil {fmt.Println(err)return}fmt.Println(resp)
}

从函数返回自定义错误 (Returning custom error from a function)

When we are writing a function of our own, there are cases when we have errors. These errors can be returned with the help of the error object:

当我们编写自己的函数时,有时会出现错误。 这些错误可以在错误对象的帮助下返回:

func Increment(n int) (int, error) {if n < 0 {// return error objectreturn nil, errors.New("math: cannot process negative number")}return (n + 1), nil
}
func main() {num := 5if inc, err := Increment(num); err != nil {fmt.Printf("Failed Number: %v, error message: %v", num, err)}else {fmt.Printf("Incremented Number: %v", inc)}
}

Most of the packages that are built in Go, or external packages we use, have a mechanism for error handling. So any function we call could have possible errors. These errors should never be ignored and always handled gracefully in the place we call these functions, as we have done in the above example.

Go中内置的大多数程序包或我们使用的外部程序包都有错误处理机制。 因此,我们调用的任何函数都可能存在错误。 就像在上面的示例中所做的那样,这些错误绝不能忽略,并且总是在我们称为这些函数的位置进行适当地处理。

恐慌 (Panic)

Panic is something that is unhandled and is suddenly encountered during a program execution. In Go, panic is not the ideal way to handle exceptions in a program. It is recommended to use an error object instead. When a panic occurs, the program execution get’s halted. The thing that gets executed after a panic is the defer.

恐慌是无法处理的,在程序执行过程中会突然遇到。 在Go中,恐慌不是处理程序中异常的理想方法。 建议改用错误对象。 发生紧急情况时,程序执行将停止。 恐慌后被执行的事情是推迟。

//Go
package mainimport "fmt"func main() {f()fmt.Println("Returned normally from f.")
}func f() {defer func() {if r := recover(); r != nil {fmt.Println("Recovered in f", r)}}()fmt.Println("Calling g.")g(0)fmt.Println("Returned normally from g.")
}func g(i int) {if i > 3 {fmt.Println("Panicking!")panic(fmt.Sprintf("%v", i))}defer fmt.Println("Defer in g", i)fmt.Println("Printing in g", i)g(i + 1)
}

延期 (Defer)

Defer is something that will always get executed at the end of a function.

延迟是始终在函数末尾执行的东西。

In the above example, we panic the execution of the program using panic(). As you notice, there is a defer statement which will make the program execute the line at the end of the execution of the program. Defer can also be used when we need something to be executed at the end of the function, for example closing a file.

在上面的示例中,我们使用panic()恐慌了程序的执行。 您会注意到,有一个defer语句,它将使程序在程序执行结束时执行该行。 当我们需要在函数末尾执行某些操作(例如关闭文件)时,也可以使用Defer。

并发 (Concurrency)

Go is built with concurrency in mind. Concurrency in Go can be achieved by Go routines which are lightweight threads.

Go在构建时考虑了并发性。 Go的并发可以通过Go例程(轻量级线程)来实现。

Go routine

例行公事

Go routines are the function which can run in parallel or concurrently with another function. Creating a Go routine is very simple. Simply by adding a keyword Go in front of a function, we can make it execute in parallel. Go routines are very lightweight, so we can create thousands of them. Let’s look into a simple example:

Go例程是可以与另一个函数并行或同时运行的函数。 创建Go例程非常简单。 只需在函数前面添加关键字Go,就可以使其并行执行。 Go例程非常轻巧,因此我们可以创建数千个例程。 让我们看一个简单的例子:

package main
import ("fmt""time"
)
func main() {go c()fmt.Println("I am main")time.Sleep(time.Second * 2)
}
func c() {time.Sleep(time.Second * 2)fmt.Println("I am concurrent")
}
//=> I am main
//=> I am concurrent

As you can see in the above example, the function c is a Go routine which executes in parallel with the main Go thread. There are times we want to share resources between multiple threads. Go prefers not sharing the variables of one thread with another because this adds a chance of deadlock and resource waiting. There is another way to share resources between Go routines: via go channels.

如上例所示,函数c是Go例程,与Go主线程并行执行。 有时我们想在多个线程之间共享资源。 Go倾向于不与另一个线程共享一个变量,因为这会增加死锁和资源等待的机会。 在Go例程之间共享资源的另一种方法是:通过go通道。

Channels

频道

We can pass data between two Go routines using channels. While creating a channel it is necessary to specify what kind of data the channel receives. Let’s create a simple channel with string type as follows:

我们可以使用通道在两个Go例程之间传递数据。 创建通道时,必须指定通道接收的数据类型。 让我们创建一个具有字符串类型的简单通道,如下所示:

c := make(chan string)

With this channel, we can send string type data. We can both send and receive data in this channel:

通过此通道,我们可以发送字符串类型的数据。 我们可以在此通道中发送和接收数据:

package mainimport "fmt"func main(){c := make(chan string)go func(){ c <- "hello" }()msg := <-cfmt.Println(msg)
}
//=>"hello"

The receiver Channels wait until the sender sends data to the channel.

接收方通道等待,直到发送方将数据发送到该通道。

One way channel

单向通道

There are cases where we want a Go routine to receive data via the channel but not send data, and also vice versa. For this, we can also create a one-way channel. Let’s look into a simple example:

在某些情况下,我们希望Go例程通过通道接收数据但不发送数据,反之亦然。 为此,我们还可以创建一个单向通道 。 让我们看一个简单的例子:

package mainimport ("fmt"
)func main() {ch := make(chan string)go sc(ch)fmt.Println(<-ch)
}func sc(ch chan<- string) {ch <- "hello"
}

In the above example, sc is a Go routine which can only send messages to the channel but cannot receive messages.

在上面的示例中, sc是Go例程,该例程只能将消息发送到通道,但不能接收消息。

使用select为Go例程组织多个通道 (Organizing multiple channels for a Go routine using select)

There may be multiple channels that a function is waiting on. For this, we can use a select statement. Let us take a look at an example for more clarity:

一个功能可能正在等待多个通道。 为此,我们可以使用select语句。 让我们看一个例子来更清楚:

package mainimport ("fmt""time"
)func main() {c1 := make(chan string)c2 := make(chan string)go speed1(c1)go speed2(c2)fmt.Println("The first to arrive is:")select {case s1 := <-c1:fmt.Println(s1)case s2 := <-c2:fmt.Println(s2)}
}func speed1(ch chan string) {time.Sleep(2 * time.Second)ch <- "speed 1"
}func speed2(ch chan string) {time.Sleep(1 * time.Second)ch <- "speed 2"
}

In the above example, the main is waiting on two channels, c1 and c2. With select case statement the main function prints, the message sends from the channel whichever it receives first.

在上面的示例中,主电源在两个通道c1和c2上等待。 使用select case语句打印主要功能,然后从该通道中首先接收的那个消息发送消息。

Buffered channel

缓冲通道

You can create a buffered channel in go. With a buffered channel, the messages send to the channel will be blocked if the buffer is full. Let’s take a look at the example:

您可以在go中创建一个缓冲通道。 使用缓冲通道时,如果缓冲区已满,则发送到该通道的消息将被阻止。 让我们看一个例子:

package mainimport "fmt"func main(){ch := make(chan string, 2)ch <- "hello"ch <- "world"ch <- "!" # extra message in bufferfmt.Println(<-ch)
}# => fatal error: all goroutines are asleep - deadlock!

As we see in above no more than 2 messages are accepted by a channel.

正如我们在上面看到的,一个通道接受的消息不超过2条。

为什么Golang成功? (Why is Golang Successful?)

Simplicity… — Rob-pike

简单……— Rob-pike

大! (Great!)

We learned some of the major components and features of Go.

我们了解了Go的一些主要组件和功能。

  1. Variables, Datatypes变量,数据类型
  2. Array slices and maps数组切片和贴图
  3. Functions功能
  4. Looping and conditional statements循环和条件语句
  5. Pointers指针
  6. Packages配套
  7. Method, Structs, and Interfaces方法,结构和接口
  8. Error Handling错误处理
  9. Concurrency — Go routines and channels并发-Go例程和通道

Congratulations, you now have a decent understanding of Go.

恭喜,您现在对Go有了一个不错的了解。

One of my most productive days was throwing away 1,000 lines of code.

我最有生产力的日子之一就是扔掉1000行代码。

— Ken Thompson

—肯·汤普森

Do not stop here. Keep moving forward. Think about a small application and start building.

不要在这里停下来。 继续前进。 考虑一个小的应用程序并开始构建。

LinkedIn, Github, Twitter

领英 , Github , 推特

Also Posted on Milap Neupane Blog: Learning Go-from zero to hero

还发布在Milap Neupane博客上: 学习从零开始走向英雄

翻译自: https://www.freecodecamp.org/news/learning-go-from-zero-to-hero-d2a3223b3d86/

围棋学习软件

围棋学习软件_学习围棋-从零到英雄相关推荐

  1. linux 下外语学习软件_学习外语如何帮助您学习编码

    linux 下外语学习软件 The road to becoming a software developer is a long and difficult one, especially for ...

  2. 高中必备学习软件_高中党必备高效学习软件

    高中党必备APP推荐,超实用的高效学习软件,正确使用快速提高分值 妹妹正在读高三.周末把她手机里的APP都打开来体验了一下.最后选了这几个软件推荐给大家.提前说明一下.我妹妹读的是理科,但是语数英相关 ...

  3. 高中必备学习软件_有哪些适合高中生的学习软件?

    先来推荐一波实质的干货推荐,必备软件!!! 『作文纸条』 这个APP真的要夸! 界面简洁,排版美观,每天都向你推送最新的素材,最重要的是里面有一群爱写作的大佬每天都在写作文!!!这么好的宝藏APP怎么 ...

  4. 高中必备学习软件_高中必备app下载-高中必备下载v2.0.7-西西软件下载

    高中必备是一款高中教育学习软件,在这里汇集了多方面科目内容,可以随时进行科目选择,拥有随机练习.真题模拟还有单元测试以及特色专题等内容,操作方法简单,需要的伙伴,在西西下载使用吧! 高中必备简介: 高 ...

  5. 华尔街英语学习软件_华尔街英语吧啦吧啦聊点啥:语言学习交流至上

    撇开学前阶段不说,现在从小学到初中.高中,再到大学,甚至到职场,英语学习似乎从未缺席,就连华尔街英语委托知名网上市场研究公司YouGov制作的<全球英语研究报告>中也显示,全球潜在英语学习 ...

  6. 没有基础能学原画吗,用什么学习软件和学习工具呢?

    很多喜欢原画的朋友们都会问到这些问题,我没有基础能学习好游戏原画嘛?对于没有基础的新人来说难学嘛?还有就是在学习原画中要用要什么学习软件和工具呢?下面我们来看下这些问题 一.没有基础能学习嘛?难学习嘛 ...

  7. 物联网课程学习目标_学习攻略|软件工程统计方法amp;amp;物联网

    软件工程统计方法 && 物联网 任课老师:余松森,葛红 课程特点及困难 本课程的主要内容涉及统计机器学习方法, 以及如何采用Python进行应用实现. 同学们在学习中主要遇到以下问题: ...

  8. animiz动画制作软件_学习动画制作需要掌握的常用软件合集

    影视动画越来越深入我们的工作和生活,其中动画的发展也深深吸引着我们的眼球. 在当下创作一部动画,大多已放下传统纸上动画的形式,开始尝试使用电脑绘图和3D方式来制作.所以,就让我们来看看常用的动画制作的 ...

  9. 儿童电脑学习软件_电脑端英语学习宝藏软件

    本人电脑:戴尔 软件名称:微软必应词典 下载渠道:软件商城即可下载 以下内容主要分享使用后 总结的软件优点以及页面功能的介绍图 (阅读时间大概需180秒,无碎碎念~) 页面截图: 页面主视图 小众亮点 ...

最新文章

  1. mysql 中lock wait_应用中MYSQL 报错Lock wait timeout exceeded; try restarting transaction
  2. 汽车之家全系车型(包含历史停售车型)图片--参数分析
  3. linux删除libc.so.6
  4. cat 几行_研发早 商用早 有方科技Cat.1产品在多个共享场景商用
  5. php自定义中文分词方法,php实现的中文分词类完整实例
  6. 银行存款都有哪些误区,你都有踩坑吗?
  7. 【IDEA】关于 IDEA 中新建 web 项目的 webapp 文件夹没有小蓝点 ,启动服务,访问不到解决方案
  8. [C++11] 新特性总结
  9. 如何跨越线程调用窗体控件?(3)
  10. 手机音频拼接软件_几款好用的修音软件,有需要的小伙伴快来下载吧
  11. ros使用RPLIDAR激光雷达
  12. Git commit --amend
  13. 【HTML】讲讲对HTML5的语义化的理解
  14. java模拟抛硬币_用随机数模拟抛硬币
  15. 数据库建模-物理层建模
  16. 常用小工具:一款好用、实用的“日常工作安排”桌面日历
  17. vue3 ref 和 reactive 区别
  18. js的join()与 split()
  19. JointJS入门实例01-在JOINTJS元素中使用HTML
  20. Pytorch Unet深入浅出

热门文章

  1. 如何加强知识产权保护?
  2. cmd如何打开某一盘符下的文件
  3. Jackson公司蛋白质电印迹方法确认蛋白质转移
  4. 怪盗基德的滑翔翼【从小白解法到DP解法】
  5. php如何写短信验证码,php发送短信验证码
  6. 面试题-基础-网格移动路径算法
  7. 《C语言杂记》解决 error c4996 ‘fopen‘ This function or variable may be unsafe
  8. 用IP段区分境内外用户
  9. 搞懂偏导数、方向导数、梯度、散度、旋度
  10. html抓取文章,网页抓取工具:一个简单的文章采集示例