零基础golang入门(四)

157 阅读5分钟

最佳的学习方式就是上手实践操作!!!

本文掌握

以下为基本语法的了解,更多用法的请查看文档

  • 变量声明
  • 结构体
  • 指针
  • 方法和接收者
  • 包与包间的调用

变量声明

详细请查看文档: 变量和常量

变量声明的格式,简单介绍以下几种

// var 变量名 变量类型
var name string// 批量声明 用括号包起来
var (
    name string
    age int
)
​
// 短变量声明,在函数内部可以使用 := 初始化变量
func main() {
    name := "小明"
}

指针

详细请查看文档:指针

只需要记住两个符号:&(取地址)和 *(根据地址取值)

使用请求看下面的:结构体结合指针的使用

结构体

详细请查看文档: 结构体

认识类型 type

go 有一些基本类型,如int、string、bool等

除了基本类型,我们还可以自定义类型(可以结合变量声明理解):

// 将MyInt定义为int类型
type MyInt int
结构体的定义格式
type 类型名 struct {
    字段名 字段类型
    字段名 字段类型
    ...
}

举例:

type person struct {
    name string
    age int8
    city string
}
// 还可以这样写
type person struct {
    name, city string
    age int8
}
结构体实例化

声明结构类型:

// var 结构体实例 结构体类型
var p1 person

使用示例:

package main
​
import "fmt"type person struct {
    name string
    city string
    age  int8
}
​
func main() {
    var p1 person
    p1.name = "李四"
    p1.city = "北京"
    p1.age = 18
    var p2 person
    p2.name = "张三"
    fmt.Printf("p1=%v\n", p1)   // p1={李四 北京 18}
    fmt.Printf("p1=%#v\n", p1)  // p1=main.person{name:"李四", city:"北京", age:18}
    fmt.Printf("p2=%v\n", p2)   // p2={张三  0}
    fmt.Printf("p2=%#v\n", p2)  // p2=main.person{name:"张三", city:"", age:0}
}

执行 go run main.go,输出对比

以上结构体可以理解为:多个字段的对象,定义为一个类型(也可以是空对象)

结构体、指针的使用

new创建指针类型结构体:

var p3 = new(person)
fmt.Printf("p3=%#v\n", p3) // p3=&main.person{name:"", city:"", age:0}

对比上面结构体实例化:

  • 声明用了 =
  • 打印的类型 多了一个 &

使用 &对结构体取地址操作,等同于用new

p4 := &person{}
fmt.Printf("p4=%#v\n", p4) // p4=&main.person{name:"", city:"", age:0}

方法和接收者

方法的格式如下:

func (接收者变量 接收者类型) 方法名(参数列表) (返回参数) {
    函数体
}

示例:

// Person 结构体
type Person struct {
    name string
    age  int8
}
​
// NewPerson 构造函数
func NewPerson(name string, age int8) *Person {
    return &Person{
        name: name,
        age:  age,
    }
}
​
// Dream Person做梦的方法
func (p Person) Dream() {
    fmt.Printf("%s的梦想是学好Go语言!\n", p.name)
}
​
// 使用指针接收者,设置age
func (p *Person) SetAge(newAge int8) {
    p.age = newAge
}
​
func main() {
    p1 := NewPerson("测试", 25)
    p1.Dream()
    p1.SetAge(30)
    fmt.Println(p1.age) // 30
}

解读示例:

// 第一个 Person 定义结构体// 第二个 NewPerson 构造函数
// return &Person{}  返回对结构体取地址操作
// 返回参数  *Person  根据地址取值,规范return返回参数类型, 记:&、*
// main 函数内使用:
// P1 := NewPerson("测试", 25)
// p1 就是 return &Person{} 返回, *Person 类型的结构体 // 第三个 Dream 构造函数
// (p Person) 
// p 接收者 Person类型,对比 SetAge// 第四个 SetAge 构造函数
// (p *Person)
// p 指针接收者 *Person指针类型,这里对接收者的内容做了设置更新,所以需要用指针接收者,指针根据地址取值,对 P1 的值做设置
// p1.SetAge(30)

包与包间的调用

以上都是在 main.go 入口文件单文件中操作

如果根据以下目录这么包与包间的调用呢?

├── gin                             为项目根目录
│ ├── Router                        为路由目录
│       └── router.go
│ ├── Models                        为模型目录
│       └── personModel.go
└── main.go                         为入口文件

根据上面这个目录结构

项目升级

这里需要再提下,下面有用到:

入门二

  依赖包管理初始化命令 go mod init xxx

入门三

  邂逅gin框架 中路由的配置,下面把路由设置移到router.go文件

对应文件内容如下:

// router.go
package router
​
import (
    "net/http""github.com/gin-gonic/gin"
)
​
func SetInit() {
    r := gin.Default()
    r.GET("/", func(c *gin.Context) {
        c.String(http.StatusOK, "hello world")
    })
​
    r.GET("gintest", func(c *gin.Context) {
        c.String(http.StatusOK, "gin test")
    })
​
    r.Run(":3250")
}
// personModel.go
package models
​
import "fmt"type Person struct {
    Name string `json:"name"`
    Age  int8   `json:"age"`
}
​
// NewPerson 构造函数
func NewPerson(name string, age int8) *Person {
    return &Person{
        Name: name,
        Age:  age,
    }
}
​
// Dream Person做梦的方法
func (p Person) Dream() {
    fmt.Printf("%s的梦想是学好Go语言!\n", p.Name)
}
​
// 使用指针接收者,设置age
func (p *Person) SetAge(newAge int8) {
    p.Age = newAge
}
// main.go
package main
​
import (
    "fmt"
    router "gin/Router"
    "gin/models"
)func main() {
    p1 := models.NewPerson("测试", 25)
    p1.Dream()
    p1.SetAge(30)
    fmt.Println(p1.Age)router.SetInit()
}

解释上面包与包间的调用

// router.go 文件
//router 为当前包名称
package router
​
// `persomModel.go 文件
// models 为当前包名称
package models
​
// main.go
// 应用本地包
import (
    router "gin/Router"
    "gin/models"
)
// router 为 router.go 定义的包名称
// "gin/Router" 
// gin: 为 go mod init XXX 依赖包管理初始化设置的 XXX,
// /Router: 包在项目中距根目录的路径
// 这样就可以调用router包里的方法执行 -> router.SetInit()  // "gin/models" 使用同上
// 调用models包里的方法 -> models.NewPerson("测试", 25)

"gin/Router" 中的 gin 为 go mod init XXX 依赖包管理初始化设置的 XXX,这也是可以修改的,在go.mod文件修改 module gin

调用router包里的方法执行 -> router.SetInit()

最后可正常运行的项目目录应该是下面这样的,多了两个文件 go.modgo.sum

├── gin                             为项目根目录
│ ├── Router                        为路由目录
│       └── router.go
│ ├── Models                        为模型目录
│       └── personModel.go
├── go.mod                          go mod init xxx 生成的包管理模块
├── go.sum                          go get github.com/xxx 下载包生成
└── main.go                         为入口文件

按这样的执行 go run main.go

$ go run main.go
测试的梦想是学好Go语言!
30
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.
​
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)
​
[GIN-debug] GET    /                         --> gin/Router.SetInit.func1 (3 handlers)
[GIN-debug] GET    /gintest                  --> gin/Router.SetInit.func2 (3 handlers)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Listening and serving HTTP on :3250

项目启动成!!!

完结

撒花~,入门系列学完了~

再续征程

进阶可以看下 go-gin-example 这个开源项目
再往前,就要靠你自己了,朋友加油!