1. Hello World

package main

import "fmt"

func main() {
	// 控制台单行输出
	fmt.Println("Hello world!")

	// 连续输出
	fmt.Print("Hello ")
	fmt.Print("world again!\n")	// \n换行

	// 中文
	fmt.Print("你好")
}

2. 变量

package main

import "fmt"

func main() {
	// using var
	var name1 string = "Zlq"
	fmt.Println(name1)

	var age1 int = 43
	fmt.Println(name1, age1)

	fmt.Printf("age1 is %T\n", age1)	// 屏幕输出变量类型 %T
	fmt.Printf("say again age1 is %d hehe\n", age1)

	// 常量定义
	const isCool = true
	//isCool = false
	fmt.Println(isCool)
	fmt.Printf("isCool is %T\n", isCool)

	// 简短定义
	name2 := "adida5"
	fmt.Printf("%s is %T\n", name2, name2)

	// 一行
	name3, email := "zlq", "zhouleqing@126.com"
	fmt.Println(name3, email)

}

3. 条件分支

package main

import "fmt"

func main() {
	// using var
	var name1 string = "Zlq"
	fmt.Println(name1)

	var age1 int = 43
	fmt.Println(name1, age1)

	fmt.Printf("age1 is %T\n", age1)	// 屏幕输出变量类型 %T
	fmt.Printf("say again age1 is %d hehe\n", age1)

	// 常量定义
	const isCool = true
	//isCool = false
	fmt.Println(isCool)
	fmt.Printf("isCool is %T\n", isCool)

	// 简短定义
	name2 := "adida5"
	fmt.Printf("%s is %T\n", name2, name2)

	// 一行
	name3, email := "zlq", "zhouleqing@126.com"
	fmt.Println(name3, email)

}

4. 循环

package main

import "fmt"

func main() {
	i := 1
	for i < 10 {
		fmt.Println(i)
		i++
	}

	for j := 0; j < 10; j++ {
		fmt.Println("Number", j)
	}

	for i := 1; i <= 100; i++ {
		if i % 5 == 0 {
			fmt.Printf("%d 是 5 的整数倍\n", i)
		}
		if i > 50 {
			break
		}
	}
}

5. 函数

package main

import "fmt"

func greeting(name string) string  {
	return "Hello " + name
}

func main() {
	fmt.Println(greeting("zlq"))
}

6. 包

目录结构:

├── main.go
└── mypackage
    ├── my_mult.go
    └── my_package.go

my_mult.go:

package mypackage

func Mult(x, y int)int  {
	r := 0
	for i := 0; i < y; i++ {
		//r = r + x
		r = plus(r, x)
	}

	return r
}

my_package.go:

package mypackage

// 大写字母开头的函数外部可以使用
func Myfunc_plus(x, y int) int {
	return x + y
}

// 包外不可以用
func plus(x, y int) int {
	return x + y
}

main.go

package main

import (
	"fmt"
	"math"                            // 用系统的包
	"mygo_test/06_packages/mypackage" //用自己的包
)

func main() {
	fmt.Println(math.Floor(1.7))
	fmt.Println(math.Ceil(1.7))
	fmt.Println(math.Sqrt(9))
	fmt.Println(mypackage.Myfunc_plus(1, 3))
	//fmt.Println(mypackage.plus(2, 4))

	fmt.Println(mypackage.Mult(3, 5))
}

7. 数组

package main

import "fmt"

func main()  {

	// 定义 再 赋值
	var fruitsArr [2]string
	fruitsArr[0] = "apple"
	fruitsArr[1] = "orange"

	fmt.Println(fruitsArr)
	fmt.Println(fruitsArr[1])

	// 定义 并 赋值
	phonesArr := []string{"iphone", "mi", "huawei", "oppo"}

	fmt.Println(phonesArr)

	// 数组长度
	length := len(phonesArr)
	fmt.Println("phonesArr 长度=", length)

	// 遍历数组
	fmt.Println("遍历方法1 for循环len(ary)")
	for i := 0; i < length; i++ {
		fmt.Println(i, phonesArr[i])
	}
	fmt.Println("遍历方法2 用range, 不想要下标索引的话 i 用_代替 (_, item := range arr)")
	for i, item := range phonesArr {
		fmt.Println(i, item)
	}

	// 增加元素
	phonesArr = append(phonesArr, "vivo")
	fmt.Println("增加元素vivo以后的数组:", phonesArr)

	// 数组切片 左包右不包
	pArr1 := phonesArr[:1]	// 从开始 切到 0
	pArr2 := phonesArr[1:3]	// 从下标1开始 切到 2
	pArr3 := phonesArr[2:]  // 从下标2开始 切到最后

	fmt.Println("[:1] 从开始切到下标是0的数组:", pArr1)
	fmt.Println("[1:3] 从下标1开始切到2的数组:", pArr2)
	fmt.Println("[2:] 从下标2开始 切到最后的数组:", pArr3)

	// 删除数组中的元素
	which := 2
	phonesArr = append(phonesArr[:which], phonesArr[which+1:]...)
	fmt.Println("删除下标是which以后的数组:", phonesArr)

}

8. Map

package main

import "fmt"

func main()  {
	// 定义map
	emails := make(map[string]string)

	// 分配键值对
	emails["张三"] = "zhangshan@gmail.com"
	emails["李四"] = "lisi@126.com"

	fmt.Println(emails)
	fmt.Println(len(emails))
	fmt.Println(emails["张三"])

	// 删除
	delete(emails, "张三")
	fmt.Println(emails)

	// 定义并初始化map
	emails2 := map[string]string{
		"张三" : "zhangsan@gmail.com",
		"王五" : "wangwu@126.com",
	}
	fmt.Println(emails2)

	// 遍历map
	for k, v := range emails2 {
		fmt.Printf("key=%s, value=%s \n", k, v)
	}
	// 遍历 key
	for k := range emails2 {
		fmt.Printf("key=%s \n", k)
	}
	// 遍历 value
	for _, v := range emails2 {
		fmt.Printf("value=%s \n", v)
	}
}

9. 指针

package main

import "fmt"

func main() {
	a := 5
	p := &a	// p是指向a的指针

	fmt.Println(a, p)
	fmt.Printf("p 的类型是 %T \n", p)

	fmt.Printf("p指向的值用*p取得: %d \n", *p)

	*p = 100
	fmt.Printf("修改*p的值为100以后, a的值: %d \n", a)
}

10. 闭包

package main

import "fmt"

func adder() func(int)int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}

func main() {
	sum := adder()
	for i := 1; i <= 10; i++ {
		fmt.Println(sum(i))
	}
}

在 Go 语言中,闭包(Closure)是一个函数值,它来自于函数体的外部的变量引用。闭包函数可以对这些引用的变量进行访问和修改,即使在其定义之后这些变量已经脱离了作用域。换句话说,闭包允许将函数作为一个变量来使用,比如可以将一个函数作为参数传递给另外一个函数。

以下是一个简单的闭包函数的示例:

func plusX(x int) func(int) int {
    return func(y int) int { return x + y }
}

func main() {
    p := plusX(10)
    fmt.Println(p(20)) // 输出 30
}

在这个例子中,函数 plusX 返回一个新的函数,这个新函数在执行时会将传入的参数与变量 x(它是 plusX 的参数)相加。在 main 函数中,我们获取了这个新函数并把其赋值给了变量 p,然后调用这个函数 p,并传入了参数 20,得到了返回值 30。

在这个例子中,x 是在 plusX 函数的内部定义的变量,但是在 plusX 函数返回的匿名函数中仍然可以被访问和修改,这就是闭包的特性。

在Go语言中,闭包(Closure)指的是一个函数值(函数变量),它引用了外部函数作用域中的变量。简单来说,闭包可以让你在一个函数中访问另一个函数中的变量。

当你在一个函数内部定义了另一个函数,并且这个内部函数访问了外部函数的局部变量,那么内部函数就成为了闭包。在闭包中,外部函数的局部变量被保留在内存中,并且可以被内部函数继续访问和操作。

下面是一个 Go 语言中的闭包的例子:

func outer() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

func main() {
    counter := outer()

    fmt.Println(counter())
    fmt.Println(counter())
}

在这个例子中,outer() 返回一个匿名函数,匿名函数可以访问 outer() 中的局部变量 count。每次调用这个匿名函数,count 的值都会增加并返回。在 main() 函数中,我们首先使用 outer() 返回的函数创建了一个新的变量 counter,并调用两次,每次调用 counter(),它都会返回一个新的自增的值。

通过闭包,我们可以实现很多更加复杂的功能,例如保持一些状态,缓存对象等。但是需要注意,过度使用闭包可能会导致内存泄漏,所以需要谨慎使用。

11. 结构体

package main

import (
	"fmt"
	"strconv"
)

// 定义结构体
type Student struct {
	name string
	gender string
	age int
}

// 结构体的方法 value reciever
func (s Student)greet() string {
	return "Hello, 我叫" + s.name + " 我今年" + strconv.Itoa(s.age) + "岁"
}

func (s Student)turnOldError()  {
	s.age++
}

// pointer reciever 想改变值需要传指针
func (s *Student)turnOld()  {
	s.age++
}

func main() {
	stu1 := Student{name: "张三", gender: "男", age: 20}
	fmt.Println(stu1)

	stu1.age++
	fmt.Println(stu1.age)

	stu2 := Student{name: "李四", gender: "女", age: 19}
	fmt.Println(stu2.greet())

	stu2.turnOldError()
	fmt.Println(stu2)

	stu2.turnOld()
	fmt.Println(stu2)
}

12. 接口

package main

import (
	"fmt"
	"math"
)

// 定义接口
type Shape interface {
	area() float64
}

type Circle struct {
	x, y, radius float64
}

type Rectangle struct {
	width, height float64
}

func (c Circle)area() float64 {
	return math.Pi * c.radius * c.radius
}

func (r Rectangle)area() float64 {
	return r.width * r.height
}

func getArea(s Shape) float64  {
	return s.area()
}

func main() {
	circle := Circle{x: 0, y:0, radius: 10}
	rectange := Rectangle{width: 5, height: 10}

	fmt.Println(getArea(circle))
	fmt.Println(getArea(rectange))
}

13. WEB

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", index)
	fmt.Println("Web server starting...")
	http.ListenAndServe(":8000", nil)
}

func index(w http.ResponseWriter, r *http.Request)  {
	fmt.Fprintf(w, "<h1>Hello web</h1>")
}

14. RESTful API

package main

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/mux"
	"log"
	"math/rand"
	"net/http"
	"strconv"
)

//book struct (Model)
type Book struct {
	ID string `json:"id"`
	ISBN string `json:"isbn"`
	Title string `json:"title"`
	Author *Author `json:"author"`
}

type Author struct {
	Firstname string `json:"firstname"`
	Lastname string `json:"lastname"`
}

// Init books var as slice Book struct
var books []Book

func getBooks(w http.ResponseWriter, r *http.Request)  {
	log.Println("Get all books")
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(books)
}

func getBook(w http.ResponseWriter, r *http.Request)  {
	w.Header().Set("Content-Type", "application/json")
	params := mux.Vars(r)

	log.Println("Get Book ", params["id"])

	for _, item := range books {
		if item.ID == params["id"] {
			json.NewEncoder(w).Encode(item)
			return
		}
	}
	json.NewEncoder(w).Encode(&Book{})
}

func creatBook(w http.ResponseWriter, r *http.Request)  {
	w.Header().Set("Content-Type", "application/json")
	var book Book
	_ = json.NewDecoder(r.Body).Decode(&book)
	book.ID = strconv.Itoa(rand.Intn(1000000))
	books = append(books, book)
	json.NewEncoder(w).Encode(book)
}

func updateBook(w http.ResponseWriter, r *http.Request)  {
	fmt.Println("Update Book")
	w.Header().Set("Content-Type", "application/json")
	var book Book
	_ = json.NewDecoder(r.Body).Decode(&book)
	params := mux.Vars(r)
	which := -1
	for i, item := range books {
		if item.ID == params["id"] {
			which = i
			break
		}
	}
	if which >= 0 {
		books[which] = book
	}

	json.NewEncoder(w).Encode(books)
}

func deleteBook(w http.ResponseWriter, r *http.Request)  {
	fmt.Println("Delete Book")
	w.Header().Set("Content-Type", "application/json")
	params := mux.Vars(r)
	for i, item := range books {
		if item.ID == params["id"] {
			books = append(books[:i], books[i+1:]...)
			break
		}
	}
	json.NewEncoder(w).Encode(books)
}

func main()  {
	fmt.Println("Hello rest api")

	r := mux.NewRouter()

	//Mock data todo implement db
	books = append(books, Book{
		ID: "01",
		ISBN: "1001",
		Title: "Book One",
		Author: &Author{
			Firstname: "zhang",
			Lastname: "san",
		},
	})
	books = append(books, Book{
		ID: "02",
		ISBN: "2002",
		Title: "Book Two",
		Author: &Author{
			Firstname: "li",
			Lastname: "si",
		},
	})


	// Route Handlers / Endpoints
	r.HandleFunc("/api/books", getBooks).Methods("GET")
	r.HandleFunc("/api/books/{id}", getBook).Methods("GET")
	r.HandleFunc("/api/books", creatBook).Methods("POST")
	r.HandleFunc("/api/books/{id}", updateBook).Methods("PUT")
	r.HandleFunc("/api/books/{id}", deleteBook).Methods("DELETE")

	log.Fatal(http.ListenAndServe(":8800", r))
}