go与beego

beego go

go

调试环境1 调试环境2

一个例子

package main

import "fmt"

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

基本语法

注意:在go中声明的变量必须使用,不然会报错。当某些参数不想使用时,使用 _ 代替

注意:字符串类型在go中是一个结构,包含指向底层数组的指针和长度,这两个部分都是8个字节,所以一共为16个字节

注意:在定义常量组时,如果不提供初值,则表示使用上一行的表达式

注意:iota只在同一个const常量组中递增,当有新的const关键字时,会重新从0计数

var age int    //变量定义
i := 1         //更简洁
i, j = j, i    //交换变量
s1 + s2        //字符串直接相加

func main() {
  _,numb,strs := numbers() //只获取函数返回值的后两个
  fmt.Println(numb,strs)
}
//一个可以返回多个值的函数
func numbers()(int,int,string){
  a , b , c := 1 , 2 , "str"
  return a,b,c
}

const a string = "hello"
b := len(a)                  //求元素数
c := unsafe.Sizeof(b)        //求字节数, c=16
fmt.Println(a, b, c)

const (
    a = iota   //0
    b          //1
    c          //2
    d = "ha"   //独立值,iota += 1
    e          //"ha"   iota += 1   使用上一行的表达式
    f = 100    //iota +=1
    g          //100  iota +=1
    h = iota   //7,恢复计数
    i          //8
    )
fmt.Println(a,b,c,d,e,f,g,h,i)

注意:只有a++,没有++a;而且a++不能直接输出

a := 10
a++
fmt.Println(a)

a := 10
ptr := &a        //指针操作
*ptr++
fmt.Println(a, *ptr)

func main() {
	a, b := 1, -1
	swap(&a, &b)
	fmt.Println(a, b)
}

func swap(x *int, y *int) {      //指针交换
	temp := *x
	*x = *y
	*y = temp
}

注意:switch-case默认带有break,如要继续执行,要用fallthrough

注意:if语句的格式

注意:select会循环检测条件,如果有满足则执行并退出

a := 10
if a < 20 {
fmt.Println("less than 20")
} else {
fmt.Println("bigger than 20")
}

注意:go中循环语句只有for,没有while;另外有break, continue

注意:go中的range可以遍历

a := 3
for i := 0; i < a; i++ {    //等价于C中的for
    fmt.Println(i)
}
j := 0
for j < a {                  //等价于C中的while
    fmt.Println(j)
    j++
}

strings := []string{"google", "runoob"}
for i, s := range strings {       //range遍历
    fmt.Println(i, s)
}

注意:go中函数默认使用值传递(形参)

函数高级用法

  • 函数作为实参:可以实现回调

  • 闭包:允许匿名函数

  • 方法:go中没有面向对象的类,通过为结构体提供方法实现

func main() {
	getSquare := func(x float64) float64 {
		return math.Sqrt(x)
	}
	fmt.Println(getSquare(9))                //函数作为实参,类python
}

//回调函数
func main() {
	testCallBack(1, callback)
	testCallBack(2, func(x int) int {
		fmt.Println("callback:", x)
		return x
	})
}

func testCallBack(x int, f func(int) int) int {
	return f(x)
}

func callback(x int) int {
	fmt.Println("callback:", x)
	return x
}
func main() {
	add_func := add(1, 2)
	fmt.Println(add_func())
	fmt.Println(add_func())
	fmt.Println(add_func())
}

// 闭包使用方法
func add(x1, x2 int) func() (int, int) {
	i := 0
	return func() (int, int) {
		i++
		return i, x1 + x2
	}
}
//Circle is struct
type Circle struct {
	radius float64
}

func main() {
	var c1 Circle
	c1.radius = 10.0
	fmt.Println(c1.getArea())
	c1.changeRadius(100)
	fmt.Println(c1.getArea())
}
//该method属于Circle类型对象的方法
func (c Circle) getArea() float64 {
	return 3.14 * c.radius * c.radius
}
//当需要改变结构体属性时,需要传结构体的指针
func (c *Circle) changeRadius(radius float64) {
	c.radius = radius
}

注意:全局变量与C++类似,相同名字时局部变量会代替全局变量

注意:局部变量和全局变量的默认值为0 (int), 0 (float),nil (pointer), false (bool)

数组

多维数组

数组作为函数的参数:是值传递,不会改变数组的值;但如果是切片的话,是指针引用,可以同步修改

func main() {
	var v1 [3]int               //数组定义
	var v2 = [5]int{1, 2, 3}
	fmt.Println(v1, v2)
}

func main() {
	var v1 [3][4]int           //3行4列的二维数组
	var v2 = [3][5]int{{1, 2, 3, 4, 5}, {0, 9, 8, 7, 6}, {3, 4, 5, 6, 7}}
	fmt.Println(v1, v2)
}

func main() {
	b := [...]int{2, 3, 4, 5}    //数组
	boo(b)
	fmt.Println(b)

	p := []int{2, 3, 4, 5}       //切片
	poo(p)
	fmt.Println(p)
}
iang
func boo(num [4]int) {
	num[0], num[len(num)-1] = num[len(num)-1], num[0]   //不对原数组产生影响
}

func poo(num []int) {
	num[0], num[len(num)-1] = num[len(num)-1], num[0]    //会对原数组产生影响
}

指针

空指针为nil,等价于nullptr

指针数组与数组指针

指向指针的指针

func main() {
	var ptr *int
	fmt.Println(ptr == nil)
}

func main() {
	a := [max]int{1, 2, 3}
	var ptr [3]*int              //指针数组
	for i := 0; i < 3; i++ {
		ptr[i] = &a[i]
		fmt.Println("address:", ptr[i], "value:", *ptr[i])
	}
}

func main() {
	a := [max]int{1, 2, 3}
	var ptr *[3]int = &a        //数组指针
	for i := 0; i < max; i++ {
		fmt.Println(&a[i], &(*ptr)[i])
	}
}

func main() {
	a := 100
	var ptr *int = &a
	var pptr **int = &ptr           //指向指针的指针
	fmt.Println(a, *ptr, **pptr)
}

结构体

结构体指针

//Complex is struct
type Complex struct {
	real float64
	imag float64
}

func main() {
	var c1 Complex
	c1.real = 1
	c1.imag = -1

	c2 := Complex{real: 1, imag: -2}
	fmt.Println(c1, c2)

	ptr := &c1                //结构体指针
	fmt.Println(*ptr)
}

切片

切片的坑

  • 一种动态数组,像vector,长度可变,可以追加元素; 非常python风格

  • 作为函数参数时,切片按引用传递,数组按值传递

  • 当把 slice 作为参数,本身传递的是值,但其内容就 byte* array,实际传递的是引用,所以可以在函数内部修改,但如果对 slice 本身做 append,而且导致 slice 进行了扩容,实际扩容的是函数内复制的一份切片,对于函数外面的切片没有变化。

  • 底层数组容量是 k 的切片 slice[i:j] 来说,其长度为 j - i ;容量为 k - i

//第一个字段表示 array 的指针,是真实数据的指针第二个是表示 slice 的长度,第三个是表示 slice 的容量。
//unsafe.Sizeof(切片)永远都是 24
struct Slice              //切片的结构
{   
    byte*    array;       // actual data
    uintgo    len;        // number of elements
    uintgo    cap;        // allocated number of elements

};
func main() {
	s1 := []int{1, 2, 3} //直接初始化
	printSlice(s1)

	s2 := make([]int, 3, 5)
	printSlice(s2)

	s3 := s1[:] //s3为s1的引用,会影响s1
	s3[0] = -1
	printSlice(s1)

	s4 := s1[0:1] //切片为原数组的引用,两者会互相影响;不包含右边界
	s4[0] = -2
	printSlice(s1)
	printSlice(s4)
	s4 = append(s4, 0) //append的时候没有超过cap,还是会影响原数组
	s4[0] = 0
	printSlice(s1)
	printSlice(s4)
	s4 = append(s4, 7, 8, 9, 10) //append的时候超过cap,会发生重新分配,与原数组无关了
	s4[0] = -111
	printSlice(s1)
	printSlice(s4)

	s5 := make([]int, len(s1)) //copy只是值复制,不会互相影响
	copy(s5, s1)
	s5[0] = -3
	printSlice(s1)
	printSlice(s5)
}

func printSlice(s []int) {
	fmt.Println(s, len(s), cap(s)) //切片元素数量和容量
}

range

同python中的range,遍历容器,一个kye-valu对

func main() {
	fmt.Println(os.Args)
	for _, arg := range os.Args {  //获取参数列表
		fmt.Println(arg)
	}
}

map集合

func main() {
	var m1 map[string]int
	m1 = make(map[string]int)
	m1["first"] = 1
	m1["second"] = 2
	fmt.Println(m1)

	m2 := make(map[string]string)
	m2["china"] = "beijign"
	fmt.Println(m2)

	for key, value := range m1 {
		fmt.Println(key, value)
	}
	delete(m1, "first")   //删除
	fmt.Println(m1)

	capital, ok := m2["American"]   //查找
	if ok {
		fmt.Println(capital)
	} else {
		fmt.Println("Not exist")
	}
}

类型转化

func main() {
	var a int = 3
	var b float32 = 9.0
	mean := b / float32(a)
	fmt.Println(mean)
}

接口

把具有共性的方法定义在一起,任何其他类型直言实现了这些方法就是实现了这些接口

type Phone interface {   //接口
	call()
}

type Nokia struct {
}

func (nikia Nokia) call() {
	fmt.Println("I am Nokia, I can call you!")
}

type Iphone struct {
}

func (iphone Iphone) call() {
	fmt.Println("I am iPhone, I can call you!")
}

func main() {
	var phone Phone
	phone = new(Nokia)   //实例化接口
	phone.call()

	phone = new(Iphone)   //实例化接口
	phone.call()
}

错误处理

//内置的错误接口
type error interface {
    Error() string
}

func Sqrt(x float64) (float64, error) {
	if x < 0 {
		return 0, errors.New("square root of negative number")
	} else {
		result := math.Sqrt(x)
		return result, nil
	}
}

func main() {
	result, err := Sqrt(-1)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(result)
}

并发

go开启一个 goroutine线程

func say(s string) {
	for i := 0; i < 5; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

func main() {      //输出没有固定顺序
	go say("hi")
	say("hello")
}

channel通道

用于在两个goroutine之间传递值来同步运行和通讯,<-用于通道方向,发送和接收

通道默认存消息和取消息都是阻塞的,只能发送一个数据,只要这个数据未被接收,则所有的发送阻塞

ch <- v    // 把 v 发送到通道 ch
v := <-ch  // 从 ch 接收数据
           // 并把值赋给 v

go func(c chan int) { //读写均可的channel c } (a)
go func(c <- chan int) { //只读的Channel } (a)
go func(c chan <- int) {  //只写的Channel } (a)

func sum(num []int, c chan int) {
	sum := 0
	for _, n := range num {
		sum += n
	}
	c <- sum
}

func main() {
	s := []int{1, 2, 4, -4, 2, 3}
	c := make(chan int)
	go sum(s[:len(s)/2], c)
	go sum(s[len(s)/2:], c)
	x := <-c
	y := <-c
	fmt.Println(x, y)
}

通道缓冲区

允许发送数据和接收数据处于异步状态,发送端的发送数据可以放在缓冲区里,接收端空闲可以去接收

但如果缓冲区满了,发送端就无法发送数据了

注意:如果通道不带缓冲,发送方会阻塞直到接收方从通道中接收了值。如果通道带缓冲,发送方则会阻塞直到发送的值被拷贝到缓冲区内;如果缓冲区已满,则意味着需要等待直到某个接收方获取到一个值。接收方在有值可以接收之前会一直阻塞

ch := make(chan int, 100)

func main() {
	c := make(chan int, 2)
	c <- 1
	c <- 2

	fmt.Println(<-c)    //先入先出
	fmt.Println(<-c)
}

遍历通道

func fibonacci(n int, c chan int) {
	x, y := 0, 1
	for i := 0; i < n; i++ {
		c <- x
		x, y = y, x+y
	}
	close(c)  // 关闭通道并不会丢失里面的数据,只是让读取通道数据的时候不会读完之后一直阻塞等待新数据写入
}

func main() {
	c := make(chan int, 10)
	go fibonacci(cap(c), c)
	// range 函数遍历每个从通道接收到的数据,因为 c 在发送完 10 个
	// 数据之后就关闭了通道,所以这里我们 range 函数在接收到 10 个数据
	// 之后就结束了。如果上面的 c 通道不关闭,那么 range 函数就不
	// 会结束,从而在接收第 11 个数据的时候就阻塞了。
	for i := range c {
		fmt.Println(i)
	}
}

beego框架

官网

beego支持MVC设计模式,将程序分成model, view, controller三个部分,视图层面向用户,模型层是核心的数据层,控制层根据视图层的指令,选取合适的数据进行操作,得到最终结果。MVC使得软件得以模块化。

支持热部署:代码更改后,不需要停止程序,直接可以看到更改

安装beego后需要配置GOPATH,之后通过bee new创建的文件都保存在GOPATH下的src下。

注意:在import包时,包前有 _ 表示先执行包内的init方法

  • router:解析路由请求的,将请求转发给响应的controller
posted @ 2020-08-02 22:03  happy_fan  阅读(130)  评论(0编辑  收藏  举报