go基本语法

1.1go语言的起源

Go语言最初由Google公司的Robert Griesemer、Ken Thompson和Rob Pike三个大牛于2007年开始设计发明,他们最终的目标是设计一种适应网络和多核时代的C语言。所以Go语言很多时候被描述为“类C语言”,或者是“21世纪的C语言”,当然从各种角度看,Go语言确实是从C语言继承了相似的表达式语法、控制流结构、基础数据类型、调用参数传值、指针等诸多编程思想。但是Go语言更是对C语言最彻底的一次扬弃,它舍弃了C语言中灵活但是危险的指针运算,还重新设计了C语言中部分不太合理运算符的优先级,并在很多细微的地方都做了必要的打磨和改变。

1.2go版本的hello,world

我们学习一门语言总是从下面这段代码开始

package main
import "fmt"
func main() {// 终端输出hello world
    fmt.Println("Hello world!")
}

和C语言相似,go语言的基本组成有:

  • 包声明,编写源文件时,必须在非注释的第一行指明这个文件属于哪个包,如package main
  • 引入包,其实就是告诉Go 编译器这个程序需要使用的包,如import "fmt"其实就是引入了fmt包。
  • 函数,和c语言相同,即是一个可以实现某一个功能的函数体,每一个可执行程序中必须拥有一个main函数。
  • 变量,Go 语言变量名由字母、数字、下划线组成,其中首个字符不能为数字。
  • 语句/表达式,在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。
  • 注释,和c语言中的注释方式相同,可以在任何地方使用以 // 开头的单行注释。以 /* 开头,并以 */ 结尾来进行多行注释,且不可以嵌套使用,多行注释一般用于包的文档描述或注释成块的代码片段。

需要注意的是:标识符是用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母和数字、下划线_组成的序列,但是第一个字符必须是字母或下划线而不能是数字。

  1. 当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);
  2. 标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected)。

就是一句话,Go的标识符严格区分大小写,以小写开头的是包外不可见,大写开头可以被外部的包使用

package main

import "fmt"

func main() {
   fmt.Println("你好,世界")
   // 1.两种定义变量,var 或者 :=  常量使用const定义
   var i1 int
   i1 = 1
   i2 := 2
   const k = 3
   fmt.Println(i1)
   fmt.Println(i2)
   fmt.Println(k)
   i := 1       // 整型
   f := 3.14    // 浮点型
   b := false   // 布尔型
   s := "hello" // 字符串
   fmt.Printf("i=%d, f=%f, b=%t, s=%s", i, f, b, s) //对应类型的占位符
}

1.3 数据类型

类型详解
布尔型布尔型的值只可以是常量 true 或者 false。
数字类型整型 int 和浮点型 float。Go 语言支持整型和浮点型数字,并且支持复数,其中位的运算采用补码。
字符串类型字符串就是一串固定长度的字符连接起来的字符序列。Go 的字符串是由单个字节连接起来的。Go 语言的字符串的字节使用 UTF-8 编码标识 Unicode 文本。
派生类型(a) 指针类型(Pointer)(b) 数组类型© 结构体类型(struct)(d) Channel 类型(e) 函数类型(f) 切片类型(g) 接口类型(interface)(h) Map 类型

对于派生类型,我们对指针,结构体,接口,Map类型单独说明

1.3.1指针

指针是一种变量,用于存储其他变量的内存地址。在Go中,指针类型表示为 *T,其中 T 是指向的数据类型。指针用于引用和操作数据的内存地址,它允许在函数之间共享数据的引用,可以减少数据的拷贝,提高程序的性能。指针的零值是 nil,表示不指向任何有效的内存地址。

var x int = 10
var p *int // 声明一个整数类型的指针
p = &x     // 将指针p指向变量x的内存地址
fmt.Println(*p) // 输出:10,通过指针访问变量x的值

1.3.2 结构体类型

结构体是一种用户自定义的复合数据类型,它允许将不同类型的数据组合在一起,创建更复杂的数据结构。结构体由一组字段(字段名和字段类型)组成,每个字段可以是不同类型的数据。结构体通常用于表示实体对象或数据记录。

type Person struct {
    Name string
    Age  int
}
var p Person
p.Name = "Alice"
p.Age = 30

1.3.3 接口类型

接口是一种抽象数据类型,用于定义对象的行为。接口描述了一组方法的签名,任何实现这些方法的类型都可以被认为实现了该接口。接口提供了多态性的概念,允许不同类型的对象以一致的方式进行处理。

package main
import "fmt"
type Shape interface {
    Area() float64
}
type Circle struct {
    Radius float64
}
func (c Circle) Area() float64 {
    return 3.14 * c.Radius * c.Radius
}

func main() {
    // 创建一个 Circle 结构体实例
    circle := Circle{Radius: 5.0}

    // 通过接口调用 Area 方法
    var shape Shape
    shape = circle // 将 Circle 实例赋值给接口
    area := shape.Area()

    fmt.Printf("圆的面积是:%f\n", area)
}

1.3.4 Map(映射)类型

映射是一种无序的键-值对数据结构,也被称为字典。在Go中,映射是一种内置的数据类型,用于将键与值关联起来。映射通常用于查找表、关联数据以及用于快速查找和检索数据。

phonebook := make(map[string]string) // 创建一个字符串到字符串的映射
phonebook["Alice"] = "123-456-789"
phone := phonebook["Alice"] // 查找键对应的值

1.4分支循环

1.4.1 if

package main

import "fmt"

func main() {
    x := 10
    if x > 5 {
        fmt.Println("x 大于 5")
    } else {
        fmt.Println("x 小于等于 5")
    }
}

1.4.2 switch

package main

import "fmt"

func main() {
    day := "Wednesday"
    switch day {
    case "Monday":
        fmt.Println("星期一")
    case "Wednesday":
        fmt.Println("星期三")
    default:
        fmt.Println("其他天")
    }
}

注意这里不需要break,

1.4.3 for

for循环用于重复执行代码块,有两种常见的方式:

基本for循环

package main

import "fmt"

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

for range 循环

package main

import "fmt"

func main() {
    nums := []int{1, 2, 3, 4, 5}
    for index, value := range nums {
        fmt.Printf("索引 %d 的值是 %d\n", index, value)
    }
}

1.4.4 while

go这个语言中没有专门的while循环,所以我们需要使用到无限循环的时候,可以使用for循环来模拟

package main
import "fmt"
func main() {
    count := 0
    for count < 5 {
        fmt.Println(count)
        count++
    }
}

1.5数组和切片操作

数组是一种固定长度的数据结构,其中每个元素都具有相同的数据类型。在Go中,数组的长度是数组类型的一部分,因此不同长度的数组被认为是不同的类型。

1.5.1 数组定义

var arr [5]int                // 声明一个包含5个整数的数组,元素初始化为零值
arr := [5]int{1, 2, 3, 4, 5}   // 使用初始化值声明并初始化数组
arr := [...]int{1, 2, 3}       // 根据初始化值自动确定数组长度

访问数组元素

arr[0] = 10      // 设置第一个元素的值为10
value := arr[2] // 获取第三个元素的值

获取数组长度

length := len(arr) // 获取数组长度,结果为5

数组的遍历

可以使用for循环遍历数组元素。

   //2.数组操作,数组定长
   var arr [3]int
   arr[0] = 1
   arr[1] = 2
   arr[2] = 3
   //切片操作,切片不定长
   brr := []int{1, 2, 4}
   fmt.Println(arr[0], brr[0])
   //循环遍历数组
   for i := 0; i < len(arr); i++ {
      fmt.Println(arr[i])
   }
   //循环遍历切片,_代表不接收参数的意思
   for _, v := range brr {
      fmt.Println(v)
   }
   for i2 := range brr {
      fmt.Println(i2)
   }

1.5.2 切片定义

切片是一种动态长度的数据结构,它基于数组构建。切片允许您动态添加或删除元素,因此更加灵活。切片由三个部分组成:指向底层数组的指针、切片的长度和切片的容量。

var slice []int                  // 声明一个整数切片,未分配底层数组
slice := []int{1, 2, 3, 4, 5}    // 使用初始化值创建切片
slice := make([]int, 5)          // 使用make函数创建长度为5的切片,元素初始化为零值
slice := make([]int, 5, 10)      // 创建长度为5、容量为10的切片

基础操作如下

添加元素:使用append函数向切片中添加元素。
slice = append(slice, 6)      // 添加元素6到切片
切片:使用切片表达式来获取部分切片。

newSlice := slice[1:4]        // 获取索引1到3的切片,不包括索引4


修改元素:通过切片修改底层数组的元素也会影响原始切片和其他切片。
slice[0] = 10                 // 修改第一个元素的值为10

删除元素:Go语言没有直接的删除切片元素的内置函数。可以通过创建新的切片来实现删除元素。
// 删除索引为2的元素
slice = append(slice[:2], slice[3:]...)

获取切片长度和容量
length := len(slice)             // 获取切片长度
capacity := cap(slice)           // 获取切片容量
切片的遍历
可以使用for循环遍历切片元素,与数组类似。
for index, value := range slice {
    // 使用 index 和 value 执行代码
}

1.6函数操作

package main

import "fmt"

func main() {
   //函数操作
   print("我是函数调用" + "\n")
   c := add(1, 2)
   print(c)

   x, y := pow(2, 3)
   fmt.Println(x, y)

   d := apply(1, 2, add)
   fmt.Println(d)
}

// 函数调用返回单个值
func add(a int, b int) int {
   return a + b
}

// 函数调用返回多个值
func pow(a int, b int) (int, int) {
   a = a * a
   b = b * b
   return a, b
}

// 函数作为参数传递
func apply(a int, b int, f func(int, int) int) int {
   return f(a, b)
}

需要注意的点:

go的函数可以返回多个值,并且可以把函数作为参数传递。

切片和数组的区别:简单地说,切片就是一种简化版的动态数组。因为动态数组的长度不固定,切片的长度自然也就不能是类型的组成部分了。数组虽然有适用它们的地方,但是数组的类型和操作都不够灵活,而切片则使用得相当广泛。切片高效操作的要点是要降低内存分配的次数,尽量保证append操作(在后续的插入和删除操作中都涉及到这个函数)不会超出cap的容量,降低触发内存分配的次数和每次分配内存大小。

1.7 goroutine

goroutine(协程)是Go语言中的一种并发执行的轻量级线程。它是Go语言并发模型的核心组成部分,与传统的操作系统线程或进程相比,Goroutine更加轻量级、高效,且易于管理。

它有两个显著的特点

1. 7.1 轻量级

Goroutine相对于传统线程非常轻量级,可以在一个应用程序中创建数千甚至数百万个Goroutine而不会导致系统资源的枯竭。这是因为Goroutine共享相同的线程池(通常是操作系统的线程池),由Go运行时系统自动调度,而不是每个Goroutine都有自己的操作系统线程。

1.7.2. 并发执行

Goroutine允许程序同时执行多个任务,而不需要显式创建和管理线程。这使得编写并发程序变得更加容易,因为您可以将任务分解为多个Goroutine,它们可以并行执行。

1.7.3 Go关键字

要创建一个Goroutine,只需使用go关键字后跟一个函数调用,就可以在新的Goroutine中执行该函数。例如:

go func() {
    // 这部分代码在新的Goroutine中执行,相当于创建了一个子线程
}()

创建一个线程的代码如下

package main

import (
	"fmt"
	"time"
)

func main() {
	// 启动一个新的Goroutine 子线程
	go func() {
		for i := 0; i < 5; i++ {
			fmt.Println("Goroutine:", i)
		}
	}()

	// 主Goroutine执行的代码 主线程
	for i := 0; i < 3; i++ {
		fmt.Println("Main Goroutine:", i)
	}

	// 等待一段时间,以便Goroutine有足够的时间执行
	time.Sleep(time.Second)
}

注意上面的代码手动休眠的做法不是最佳选择,可以使用对应的同步机制,代码如下

package main

import (
	"fmt"
	"sync"
)

func main() {	
var wg sync.WaitGroup // 创建一个等待组

	// 增加等待组计数,表示有一个Goroutine正在执行
	wg.Add(1)

	// 启动一个新的Goroutine
	go func() {
		defer wg.Done() // 减少等待组计数,表示Goroutine执行完毕
		for i := 0; i < 100; i++ {
			fmt.Println("子线程:", i)
		}
	}()

	// 主Goroutine执行的代码
	for i := 0; i < 200; i++ {
		fmt.Println("Main 主线程:", i)
	}

	// 等待所有Goroutines完成
	wg.Wait() // 等待等待组中的计数归零,表示所有Goroutines都已完成

	fmt.Println("所有线程执行完毕")
    
}

1.7.4 自动调度

Go运行时系统会自动管理Goroutine的调度,包括将Goroutines分配给可用的线程,管理线程池,以及在Goroutine阻塞时将线程切换到其他Goroutines。这样,程序员无需手动管理线程的创建和销毁,也无需担心死锁等并发问题。

1.7.5 通信通过通道

Goroutines之间的通信通常通过通道(Channel)进行。通道提供了一种同步的方式,用于在Goroutines之间传递数据和进行通信。通过通道,Goroutines可以安全地共享数据,避免竞态条件和数据竞争

1.8 Channel

Go 语言之所以开始流行起来,很大一部分原因是因为它自带的并发机制。如果说 goroutine 是 Go语言程序的并发体的话,那么 channel(信道) 就是 它们之间的通信机制。channel,是一个可以让一个 goroutine 与另一个 goroutine 传输信息的通道,我把他叫做信道,也有人将其翻译成通道,二者都是一个概念。信道,就是一个管道,连接多个goroutine程序 ,它是一种队列式的数据结构,遵循先入先出的规则。

Channel(通道)是Go语言中用于在不同goroutine之间传递数据和进行通信的重要机制。通道提供了一种同步的方式,确保数据的安全传递,并且可以帮助协调不同goroutine的执行。

1.8.1 创建通道

可以使用make函数创建一个通道,指定通道中元素的类型:

信道实例 := make(chan 信道类型)
ch := make(chan int) // 创建一个整数类型的通道

1.8.2 发送和接收数据

  • 使用<-操作符来发送数据到通道。
  • 使用<-操作符从通道接收数据。
ch <- 42 // 将整数42发送到通道
value := <-ch // 从通道中接收一个整数并将其赋给变量value
close(ch) //关闭信道
x, ok := <-ch //当从信道中读取数据时,可以有多个返回值,其中第二个可以表示 信道是否被关闭,如果已经被关闭,ok 为 false,若还没被关闭,ok 为true。

1.8.3信道的长度与容量

一般创建信道都是使用 make 函数,make 函数接收两个参数

第一个参数:必填,指定信道类型

第二个参数:选填,不填默认为0,指定信道的容量(可缓存多少数据)

对于信道的容量,很重要,这里要多说几点:

当容量为0时,说明信道中不能存放数据,在发送数据时,必须要求立马有人接收,否则会报错。此时的信道称之为无缓冲信道

当容量为1时,说明信道只能缓存一个数据,若信道中已有一个数据,此时再往里发送数据,会造成程序阻塞。 利用这点可以利用信道来做锁。

当容量大于1时,信道中可以存放多个数据,可以用于多个协程之间的通信管道,共享资源。

至此我们知道,信道就是一个容器。若将它比做一个纸箱子

它可以装10本书,代表其容量为10,当前只装了1本书,代表其当前长度为1

信道的容量,可以使用 cap 函数获取 ,而信道的长度,可以使用 len 长度获取。

package main

import "fmt"

func main() {
    pipline := make(chan int, 10)
    fmt.Printf("信道可缓冲 %d 个数据\n", cap(pipline))
    pipline<- 1
    fmt.Printf("信道中当前有 %d 个数据", len(pipline))
}

输出如下

信道可缓冲 10 个数据
信道中当前有 1 个数据

1.8.4信道的类型

缓冲信道

允许信道里存储一个或多个数据,这意味着,设置了缓冲区后,发送端和接收端可以处于异步的状态。

pipline := make(chan int, 10)

无缓冲信道

在信道里无法存储数据,这意味着,接收端必须先于发送端准备好,以确保你发送完数据后,有人立马接收数据,否则发送端就会造成阻塞,原因很简单,信道中无法存储数据。也就是说发送端和接收端是同步运行的。

pipline := make(chan int)

// 或者
pipline := make(chan int, 0)

双向信道与单向信道

通常情况下,我们定义的信道都是双向通道,可发送数据,也可以接收数据。

但有时候,我们希望对信道的数据流向做一些控制,比如这个信道只能接收数据或者这个信道只能发送数据。

因此,就有了 双向信道单向信道 两种分类。

双向信道

默认情况下你定义的信道都是双向的,比如下面代码

import (
    "fmt"
    "time"
)

func main() {
    pipline := make(chan int)

    go func() {
        fmt.Println("准备发送数据: 100")
        pipline <- 100
    }()

    go func() {
        num := <-pipline
        fmt.Printf("接收到的数据是: %d", num)
    }()
    // 主函数sleep,使得上面两个goroutine有机会执行
    time.Sleep(1)
}

单向信道

单向信道,可以细分为 只读信道只写信道

定义只读信道

var pipline = make(chan int)
type Receiver = <-chan int 
var receiver Receiver = pipline

定义只写信道

var pipline = make(chan int)
type Sender = chan<- int  
var sender Sender = pipline

仔细观察,区别在于 <- 符号在关键字 chan 的左边还是右边。

<-chan 表示这个信道,只能从里发出数据,对于程序来说就是只读

chan<- 表示这个信道,只能从外面接收数据,对于程序来说就是只写

需要注意的点

信道本身就是为了传输数据而存在的,如果只有接收者或者只有发送者,那信道就变成了只入不出或者只出不入了吗,没什么用。所以只读信道和只写信道,唇亡齿寒,缺一不可。

import (
    "fmt"
    "time"
)
 //定义只写信道类型
type Sender = chan<- int  
//定义只读信道类型
type Receiver = <-chan int 
func main() {
    var pipline = make(chan int)
    go func() {
        var sender Sender = pipline
        fmt.Println("准备发送数据: 100")
        sender <- 100
    }()
    go func() {
        var receiver Receiver = pipline
        num := <-receiver
        fmt.Printf("接收到的数据是: %d", num)
    }()
    // 主函数sleep,使得上面两个goroutine有机会执行
    time.Sleep(1)
}

1.8.4 遍历信道

遍历信道,可以使用 for 搭配 range关键字,在range时,要确保信道是处于关闭状态,否则循环会阻塞。

func fibonacci(mychan chan int) {
    n := cap(mychan)
    x, y := 1, 1
    for i := 0; i < n; i++ {
        mychan <- x
        x, y = y, x+y
    }
    // 记得 close 信道
    // 不然主函数中遍历完并不会结束,而是会阻塞。
    close(mychan)
}

func main() {
    pipline := make(chan int, 10)

    go fibonacci(pipline)
    // 取值
    for k := range pipline {
        fmt.Println(k)
    }
}

1.8.5示例代码

package main

import (
	"fmt"
	"sync"
)
func main() {
ch := make(chan int)
var wg sync.WaitGroup

// 增加等待组计数,表示有两个Goroutines需要等待
wg.Add(2)
// 启动一个Goroutine向通道发送数据
go func() {
   defer wg.Done()
   for i := 1; i <= 5; i++ {
      ch <- i
   }
   close(ch)
}()
// 启动另一个Goroutine从通道接收数据
go func() {
   defer wg.Done()
   for num := range ch {
      fmt.Printf("接收到数据:%d\n", num)
   }
}()
// 等待所有Goroutines完成
wg.Wait()
fmt.Println("所有Goroutines完成")
}

1.8.6注意事项

在Go语言中,panic 是一种表示程序发生严重错误的机制。当程序在运行时遇到无法处理的错误或异常情况时,它会触发 panic,导致程序立即终止。panic 是一种在运行时引发的异常,类似于其他编程语言中的异常或错误。

关闭一个未初始化的 channel 会产生 panic

重复关闭同一个 channel 会产生 panic

向一个已关闭的 channel 发送消息会产生 panic

从已关闭的 channel 读取消息永远不会阻塞,并且会返回一个为 false 的值,用以判断该 channel 是否已关闭(x,ok := <- ch)

channel 在 Golang 中是一等公民,它是线程安全的,面对并发问题,应首先想到 channel。

1.9 go-zero框架

1.9.1安装

可参考:https://go-zero.dev/docs/tasks

1.9.2初体验

1.先创建一个名为godemo_dev的go项目,我这里用的是idea创建,goland和vscode都可以,

2.创建一个godemo_dev.api的文件
在这里插入图片描述

3.在godemo_dev.api文件中输入以下内容

syntax = "v1"
type (
	//1.用户表
	AddSysUserRequest {
		Name     string `json:"realname"`
		Username string `json:"username"`
		Address  string `json:"address"`
		Status   int64  `json:"status"` //0代表启用,1代表禁用
		Password string `json:"password"`
		Sex      int64  `json:"sex"` //0代表男,1代表女
		Phone    string `json:"phone"`
		Email    string `json:"email"`
		CreateBy int64  `json:"createBy"`
	}

	AddSysUserResponse {
		Id int64 `json:"id"`
	}

	DeleteSysUserRequest {
		Id int64 `path:"id"`
	}

	UpdateSysUserRequest {
		Id       int64  `json:"id"`
		Username string `json:"username"`
		Address  string `json:"address"`
		Status   int64  `json:"status"`
		Password string `json:"password"`
		Sex      int64  `json:"sex"`
		Phone    string `json:"phone"`
		Email    string `json:"email"`
		CreateBy int64  `json:"createBy"`
	}
	Page {
		CurPage  int64 `json:"curPage,default=1"`
		PageSize int64 `json:"pageSize,default=10"`
	}
	QuerySysUserRequest {
		Keyword string `json:"keyword,optional"`
		Page
	}

	QuerySysUserResponse {
		List  interface{} `json:"list"`
		Total int64       `json:"total"`
	}
)
service godemo_dev {
	//1.系统用户模块
	@doc(summary: "增加系统用户")
	@handler addSysUser
	post /sys-user/add (AddSysUserRequest)

	@doc(summary: "删除系统用户")
	@handler deleteSysUser
	delete /sys-user/delete/:id (DeleteSysUserRequest)

	@doc(summary: "更新系统用户")
	@handler updateSysUser
	put /sys-user/update (UpdateSysUserRequest)

	@doc(summary: "查询系统用户")
	@handler querySysUser
	post /sys-user/query (QuerySysUserRequest) returns (QuerySysUserResponse)
}

4.执行以下命令

goctl api go -api godemo_dev.api -dir .

项目结构目录如下

在这里插入图片描述

这个时候如果发现代码报错,可以删除go.mod,重新生成依赖

在这里插入图片描述

打开终端执行下面的命令,重新导入依赖

go mod init godemo_dev

go mod tidy

此时代码已经不报错了,

5.在项目中创建model文件夹

然后在终端进入到model目录,执行命令

goctl model mysql datasource --url “root:你的密码@tc
p(你的地址:3306)/meijumeihu” -t=‘sys_user’ .

此时自动生成数据库相关代码
在这里插入图片描述

6 最后需要修改两个文件

在这里插入图片描述

修改的文件如下

config.go修改如下

package config

import (
	"github.com/zeromicro/go-zero/core/stores/redis"
	"github.com/zeromicro/go-zero/rest"
)
type Config struct {
	rest.RestConf
	MysqlUrl string  //添加mysql连接
}

servicecontext.go修改如下

package svc

import (
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"godemo/internal/config"
	"godemo/model"
)

type ServiceContext struct {
	SysUserModel model.SysUserModel
	Config       config.Config
}

func NewServiceContext(c config.Config) *ServiceContext {
	conn := sqlx.NewMysql(c.MysqlUrl)
	sysUserModel := model.NewSysUserModel(conn)
	return &ServiceContext{
		SysUserModel: sysUserModel,
		Config:       c,
	}
}

最后修改以下我们的配置文件godemodev.yaml

Name: godemo_dev
Host: 0.0.0.0
Port: 8888
MysqlUrl: "用户名:密码@tcp(地址:3306)/数据库名称?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai"

go-zero配置基本完毕,剩下的就是撸代码了

o/core/stores/redis"
“github.com/zeromicro/go-zero/rest”
)
type Config struct {
rest.RestConf
MysqlUrl string //添加mysql连接
}


servicecontext.go修改如下

```go
package svc

import (
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"godemo/internal/config"
	"godemo/model"
)

type ServiceContext struct {
	SysUserModel model.SysUserModel
	Config       config.Config
}

func NewServiceContext(c config.Config) *ServiceContext {
	conn := sqlx.NewMysql(c.MysqlUrl)
	sysUserModel := model.NewSysUserModel(conn)
	return &ServiceContext{
		SysUserModel: sysUserModel,
		Config:       c,
	}
}

最后修改以下我们的配置文件godemodev.yaml

Name: godemo_dev
Host: 0.0.0.0
Port: 8888
MysqlUrl: "用户名:密码@tcp(地址:3306)/数据库名称?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai"

go-zero配置基本完毕,剩下的就是撸代码了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值