This is a creation in Article, where the information may have evolved or changed.
Weekend weather is not good, can only stay at home, so on the way to see the go language, feel more interesting, so write an article introduction. I want to write an article that you can get an initial understanding of a language when you commute by subway or bus . Therefore, the following article is mainly based on code and comments. Just need you to C language, Unix,python have a little foundation, I believe you will read in about 30 minutes and have some preliminary understanding of the go language.
Hello World
File name Hello.go
package main //声明本文件的package名import "fmt" //import语言的fmt库——用于输出func main() { fmt.Println("hello world")}
Run
You can have two modes of operation,
Explanation Execution (actually compiled into a.out and then executed)
$go run hello.gohello world
Compile execution
$go build hello.go$lshello hello.go$./hellohello world
Your own package
You can use the GOPATH environment variable or use a relative path to import your own package.
The conventions of Go are this:
- In import, you can use a relative path, such as./or: /To quote your package
- If you do not use a relative path, go will look for the $gopath/src/directory.
Using relative paths
import "./haoel" //import当前目录里haoel子目录里的所有的go文件
Using the Gopath path
import "haoel" //import 环境变量 $GOPATH/src/haoel子目录里的所有的go文件
FMT output format
The FMT Pack and the heap in the libc use printf, scanf,fprintf,fscanf very similar. The following things are not unfamiliar to C programmers.
Note: println is not supported, and printf supports the output of the% type:
package mainimport "fmt"import "math"func main() { fmt.Println("hello world") fmt.Printf("%t\n", 1==2) fmt.Printf("二进制:%b\n", 255) fmt.Printf("八进制:%o\n", 255) fmt.Printf("十六进制:%X\n", 255) fmt.Printf("十进制:%d\n", 255) fmt.Printf("浮点数:%f\n", math.Pi) fmt.Printf("字符串:%s\n", "hello world")}
Of course, you can also use the same control characters as the C language, such as \n\t\r
Variables and constants
Variables are declared much like JavaScript, using the var keyword. Note:Go is a static type of language , the following is the code:
//声明初始化一个变量var x int = 100var str string = "hello world"</pre>//声明初始化多个变量var i, j, k int = 1, 2, 3//不用指明类型,通过初始化值来推导var b = true //bool型
There is also a way to define variables (which reminds me of the Pascal language, but completely different)
x := 100 //等价于 var x int = 100;
Constants are simple, using the Const keyword:
const s string = "hello world"const pi float32 = 3.1415926
Array
Look directly at the code (note the For statement, and C very similar to it, there is no parentheses)
func main() { var a [5]int fmt.Println("array a:", a) a[1] = 10 a[3] = 30 fmt.Println("assign:", a) fmt.Println("len:", len(a)) b := [5]int{1, 2, 3, 4, 5} fmt.Println("init:", b) var c [2][3]int for i := 0; i < 2; i++ { for j := 0; j < 3; j++ { c[i][j] = i + j } } fmt.Println("2d: ", c)}
Operation Result:
array a: [0 0 0 0 0]assign: [0 10 0 30 0]len: 5init: [1 2 3 4 5]2d: [[0 1 2] [1 2 3]]
Slicing operations on arrays
This is Python.
a := [5]int{1, 2, 3, 4, 5}b := a[2:4] // a[2] 和 a[3],但不包括a[4]fmt.Println(b)b = a[:4] // 从 a[0]到a[4],但不包括a[4]fmt.Println(b)b = a[2:] // 从 a[2]到a[4],且包括a[2]fmt.Println(b)
Branch Loop statements
If statement
NOTE: The IF statement has no parentheses and must have curly braces
//if 语句if x % 2 == 0 { //...}//if - elseif x % 2 == 0 { //偶数...} else { //奇数...}//多分支if num < 0 { //负数} else if num == 0 { //零} else { //正数}
Switch statement
NOTE: The switch statement has no break and can also use a comma case multiple values
switch i { case 1: fmt.Println("one") case 2: fmt.Println("two") case 3: fmt.Println("three") case 4,5,6: fmt.Println("four, five, six") default: fmt.Println("invalid value!")}
For statement
You've seen it before, and here's a look at the three forms of For: (Note: There is no while in the Go language)
//经典的for语句 init; condition; postfor i := 0; i<10; i++{ fmt.Println(i)}//精简的for语句 conditioni := 1for i<10 { fmt.Println(i) i++}//死循环的for语句 相当于for(;;)i :=1for { if i>10 { break } i++}
About semicolons
From the code above we can see that there is no semicolon in the code. In fact, like C, Go's formal syntax uses semicolons to terminate the statement. Unlike C, these semicolons are automatically inserted by the lexical analyzer in the process of scanning the source code using simple rules, so the input source code does not require a semicolon most of the time.
The rule is this: if the last token in front of a new line is an identifier (including int
words like and float64
such), a basic value such as text, or one of the following tags, a semicolon is inserted automatically:
Break continue Fallthrough return + +--)}
Usually the Go program for
uses semicolons only in circular statements to separate initializers, conditions, and increment cells. If you write multiple statements in a row, you also need to separate them with semicolons.
Note : You should not place the left brace of a control structure ( if
, for
, switch
or select
) on the next line at any time. If you do this, a semicolon will be inserted in front of the curly braces, which may result in unwanted results .
Map
Map in other languages may be called hash table or called Dict, the following is the code related to map operation, the code is easy to understand
func main(){ m := make(map[string]int) //使用make创建一个空的map m["one"] = 1 m["two"] = 2 m["three"] = 3 fmt.Println(m) //输出 map[three:3 two:2 one:1] (顺序在运行时可能不一样) fmt.Println(len(m)) //输出 3 v := m["two"] //从map里取值 fmt.Println(v) // 输出 2 delete(m, "two") fmt.Println(m) //输出 map[three:3 one:1] m1 := map[string]int{"one": 1, "two": 2, "three": 3} fmt.Println(m1) //输出 map[two:2 three:3 one:1] (顺序在运行时可能不一样) for key, val := range m1{ fmt.Printf("%s => %d \n", key, val) /*输出:(顺序在运行时可能不一样) three => 3 one => 1 two => 2*/ }}
Pointer
Go language has pointers, see Code
var i int = 1var pInt *int = &i//输出:i=1 pInt=0xf8400371b0 *pInt=1fmt.Printf("i=%d\tpInt=%p\t*pInt=%d\n", i, pInt, *pInt)*pInt = 2//输出:i=2 pInt=0xf8400371b0 *pInt=2fmt.Printf("i=%d\tpInt=%p\t*pInt=%d\n", i, pInt, *pInt)i = 3//输出:i=3 pInt=0xf8400371b0 *pInt=3fmt.Printf("i=%d\tpInt=%p\t*pInt=%d\n", i, pInt, *pInt)
Go has two mechanisms for allocating memory, namely the built-in function new and make. They do things differently, they apply different types, which can cause confusion, but the rules are simple.
Memory allocation
New is a built-in function that allocates memory, but unlike the work of new in other languages with the same name, it simply zeroed out the memory instead of initializing the memory. New (t) assigns a zero-value storage space and returns the address, which is a value of type *t, to a project of type T. In the terms of Go, it returns a pointer to the newly assigned 0 value of type T .
make(T,
args )
The purpose of the function is new(T)
different. It is used only to create slices, maps, and Chan (message Pipelines) and returns T
*T
an initialized (not 0 ) instance of the type (not). This difference arises because these three types are essentially references to data structures that must be initialized before they are used. For example, a slice is a descriptor with three items of content, including pointers, lengths, and capacities that point to data (inside an array), and the slice value is before the three items are initialized nil
. For slices, mappings, and channels, the make
internal data structures are initialized and the values that will be used are prepared. Such as:
The following code assigns an integer array with a length of 10, a capacity of 100, and a slice that returns the first 10 arrays
make([]int, 10, 100)
The following example illustrates new
the make
difference.
var p *[]int = new([]int) // 为切片结构分配内存;*p == nil;很少使用var v []int = make([]int, 10) // 切片v现在是对一个新的有10个整数的数组的引用// 不必要地使问题复杂化:var p *[]int = new([]int)fmt.Println(p) //输出:&[]*p = make([]int, 10, 10)fmt.Println(p) //输出:&[0 0 0 0 0 0 0 0 0 0]fmt.Println((*p)[2]) //输出: 0// 习惯用法:v := make([]int, 10)fmt.Println(v) //输出:[0 0 0 0 0 0 0 0 0 0]
Function
To be honest, I'm a little bit dissatisfied with the go language, which in turn declares the variable type and the function return value (keeping the same as C?). Oh
package mainimport "fmt"func max(a int, b int) int { //注意参数和返回值是怎么声明的 if a > b { return a } return b}func main(){ fmt.Println(max(4, 5))}
function returns multiple values
Many of the package in Go will return two values, one is normal and one is error, as follows:
package mainimport "fmt"func main(){ v, e := multi_ret("one") fmt.Println(v,e) //输出 1 true v, e = multi_ret("four") fmt.Println(v,e) //输出 0 false //通常的用法(注意分号后有e) if v, e = multi_ret("four"); e { // 正常返回 }else{ // 出错返回 }}func multi_ret(key string) (int, bool){ m := map[string]int{"one": 1, "two": 2, "three": 3} var err bool var val int val, err = m[key] return val, err}
Function indeterminate parameter
The example is clear, and I'm not going to say much.
func sum(nums ...int) { fmt.Print(nums, " ") //输出如 [1, 2, 3] 之类的数组 total := 0 for _, num := range nums { //要的是值而不是下标 total += num } fmt.Println(total)}func main() { sum(1, 2) sum(1, 2, 3) //传数组 nums := []int{1, 2, 3, 4} sum(nums...)}
function closures
Nextnum This function returns an anonymous function that remembers the value of I+j in Nextnum and changes the value of i,j, thus forming a closure usage
func nextNum() func() int { i,j := 1,1 return func() int { var tmp = i+j i, j = j, tmp return tmp }}//main函数中是对nextNum的调用,其主要是打出下一个斐波拉契数func main(){ nextNumFunc := nextNum() for i:=0; i<10; i++ { fmt.Println(nextNumFunc()) }}
Recursion of functions
and c are basically the same
func fact(n int) int { if n == 0 { return 1 } return n * fact(n-1)}func main() { fmt.Println(fact(7))}
Structural body
The structure of Go is basically the same as C, but somewhat different during initialization, go supports initialization with a name.
type Person struct { name string age int email string}func main() { //初始化 person := Person{"Tom", 30, "tom@gmail.com"} person = Person{name:"Tom", age: 30, email:"tom@gmail.com"} fmt.Println(person) //输出 {Tom 30 tom@gmail.com} pPerson := &person fmt.Println(pPerson) //输出 &{Tom 30 tom@gmail.com} pPerson.age = 40 person.name = "Jerry" fmt.Println(person) //输出 {Jerry 40 tom@gmail.com}}
Structure method
Don't say more, look at the code.
Note: There is no public, protected, or private keyword in the go language, so if you want a method to be accessible by another package, you need to capitalize the first letter of the method. This is a convention .
type rect struct { width, height int}func (r *rect) area() int { //求面积 return r.width * r.height}func (r *rect) perimeter() int{ //求周长 return 2*(r.width + r.height)}func main() { r := rect{width: 10, height: 15} fmt.Println("面积: ", r.area()) fmt.Println("周长: ", r.perimeter()) rp := &r fmt.Println("面积: ", rp.area()) fmt.Println("周长: ", rp.perimeter())}
Interfaces and polymorphic
Interface means polymorphic, here is a classic example, don't say more, look at the code yourself.
//---------- 接 口 --------//type shape interface { area() float64 //计算面积 perimeter() float64 //计算周长}//--------- 长方形 ----------//type rect struct { width, height float64}func (r *rect) area() float64 { //面积 return r.width * r.height}func (r *rect) perimeter() float64 { //周长 return 2*(r.width + r.height)}//----------- 圆 形 ----------//type circle struct { radius float64}func (c *circle) area() float64 { //面积 return math.Pi * c.radius * c.radius}func (c *circle) perimeter() float64 { //周长 return 2 * math.Pi * c.radius}// ----------- 接口的使用 -----------//func interface_test() { r := rect {width:2.9, height:4.8} c := circle {radius:4.3} s := []shape{&r, &c} //通过指针实现 for _, sh := range s { fmt.Println(sh) fmt.Println(sh.area()) fmt.Println(sh.perimeter()) }}
Error handling –error interface
Function error return is probably the most tangled thing in C + +, Go's multivalued return can make it easier for us to return an error, it can return a regular return value, but also easily returned a detailed error description. Typically, the error is in the wrong type, and it has a built-in interface.
type error interface { Error() string}
Let's look at an example:
package mainimport "fmt"import "errors"//自定义的出错结构type myError struct { arg int errMsg string}//实现Error接口func (e *myError) Error() string { return fmt.Sprintf("%d - %s", e.arg, e.errMsg)}//两种出错func error_test(arg int) (int, error) { if arg < 0 { return -1, errors.New("Bad Arguments - negtive!") }else if arg >256 { return -1, &myError{arg, "Bad Arguments - too large!"} } return arg*arg, nil}//相关的测试func main() { for _, i := range []int{-1, 4, 1000} { if r, e := error_test(i); e != nil { fmt.Println("failed:", e) } else { fmt.Println("success:", r) } }}
After running the program output:
failed: Bad Arguments - negtive!success: 16failed: 1000 - Bad Arguments - too large!
Error handling –defer
The following programs are unfamiliar to everyone who is familiar with the C language (problems with resource leaks), and C + + uses RAII to solve this problem.
func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return } dst, err := os.Create(dstName) if err != nil { return } written, err = io.Copy(dst, src) dst.Close() src.Close() return}
The go language introduces defer to ensure that files that are opened can be closed. As follows: (This solution is still more elegant)
func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return } defer src.Close() dst, err := os.Create(dstName) if err != nil { return } defer dst.Close() return io.Copy(dst, src)}
Go's defer statement presets a function call (the deferred function), which runs immediately when the function executes defer returns. This method appears to be different from the conventional, but it is very effective to deal with the above situation, no matter how the function returns, must be the release of resources.
Let's look at an example of a defer function:
for i := 0; i < 5; i++ { defer fmt.Printf("%d ", i)}
The deferred function executes in a last-in, first-out (LIFO) line, so the above code will print 4 3 2 1 0 on return.
In short, I personally feel that the function of defer is a bit strange, I have not fully figured out yet.
Error handling –panic/recover
For unrecoverable errors, go provides an built-in panic function that creates a run-time error and causes the program to stop (rather violent). The function receives an arbitrary type (often a string) to be printed when the program dies. When the compiler checks for a panic at the end of the function, it stops the regular return statement check.
The following is just an example. The actual library function should avoid panic. If the problem is tolerable, it is best to keep things going rather than terminating the entire program.
var user = os.Getenv("USER")func init() { if user == "" { panic("no value for $USER") }}
When panic is called, it immediately stops execution of the current function and begins to step through the function stack, running all defer functions. If the undo reaches the top of the stack, the program dies. However, you can also use the built-in recover function to regain control of the go and return to normal execution. The call to recover notifies the undo stack and returns the parameters passed to the panic. Because only the code that runs during the undo is in a function that is defer, recover is only useful inside the deferred function.
You can simply understand that recover is used to capture Painc, preventing the program from hanging up all at once.
Here is a routine, very simple, does not explain
func g(i int) { if i>1 { fmt.Println("Panic!") panic(fmt.Sprintf("%v", i)) }}func f() { defer func() { if r := recover(); r != nil { fmt.Println("Recovered in f", r) } }() for i := 0; i < 4; i++ { fmt.Println("Calling g with ", i) g(i) fmt.Println("Returned normally from g.") }}func main() { f() fmt.Println("Returned normally from f.")}
The result of the operation is as follows: (we can see that the for loop after Painc has not been executed, but the main program is still going down)
Calling g with 0Returned normally from g.Calling g with 1Returned normally from g.Calling g with 2Panic!Recovered in f 2Returned normally from f.
Are you used to this way of programming? I think it's a little weird. Oh.
Well, here is a go language-related programming grammar introduction, I do not have all the details, just to let you know what the go language look like. Of course, this is not the end, please look forward to the next--go language features .
(Reprint this site article please indicate the author and source cool shell –coolshell.cn, do not use for any commercial purposes)