结构体之前呢,我们先谈谈数据类型,这里我们有基础类型外,还可以自定义类型和给类型设置别名。
- 两者都可以使用type来设置,如下
- 可以很清楚的看到哈,加了等号就是设置别名,不加就是自定义类型哈。
- 那么我们结构体也是要用到type的,再加上struct , 这个和c/c++里面的差不多哈
type 类型名 struct {
字段名 字段类型
字段名 字段类型
。。。。
}
- 意思的话,就跟java里面的类一样,举个例子
- 还可以使用匿名的结构体,临时用一下的时候定义。
package main
import "fmt"
// 一个人的类型
type person struct {
name string
age int
gender string
hobby []string
}
func main() {
var sb person
sb.name = "骚包"
sb.age = 18
sb.gender = "男"
sb.hobby = []string{"打篮球", "看妹妹"}
fmt.Printf("%#v", sb)
fmt.Println()
var kk = person{
name: "科科",
age: 14,
gender: "女",
}
fmt.Println(kk)
as := person{
"阿水",
12,
"男",
[]string{"打篮球"},
}
fmt.Println(as)
}
- 一共三种方式
- 第一种:通过声明变量,通过变量来传入值
- 第二种,通过key/value的形式来直接输入值
- 第三种,类似全部属性的构造器一样的输入值,按照顺序
- go里面的方法跟java区别还是满大的,go的方法其实就是一个函数,但是要求限定了调用的结构体
- 如下:
func main() {
ans := newDog("骚包", 18)
ans.wang()
}
- 这样子看,是不是很明显了,通过变量.wang()的形式就可以调用了,这个倒是跟java里面一样,啊哈哈哈哈哈
在go里面哈,如果标识符首字母大写了,就表示对外部包可见(暴露的,公有的)
- 上面的 (d dog) 这个就是接受者,用来指定被调用的对象
- 接受者,也会分为, 值接受者, 和 指针接受者
- 上图解释,因为我知道,代码别说你不看了,我也不会看呀,啊哈哈哈哈哈
- 可以看出来哈,初始化的时候他是18岁
- 调用值接收者呢,年龄没有发生改变哈,
- 但是调用 指针接收者, 年龄就发生了改变
- 这是因为,go里面全部都是值传递,复制粘贴的形式,CV的意思,值传递后进行修改,改的是传过去的副本,而不是原数据,所以不会发生改变,
- 但是指针就直接指向的是原数据。
学了这么久了,我们来搞个学生管理系统吧1.需要修改接收者里面的值
2.接收者是拷贝比较大的大对象
3.保证一致性,如果有某个方法使用了指针接收者,那么其他方法也要使用指针接收者
package main
import (
"fmt"
"os"
)
// 学生类
type student struct {
id int64
name string
}
// 构造器
func newStudent(id int64, name string) *student {
return &student{
id,
name,
}
}
// 设置一个容器,用来装学生
var (
allStu map[int64]*student
)
// 展示所有学生
func allStudent() {
for k, v := range allStu {
fmt.Printf("学号:%d 姓名:%sn", k, v.name)
}
}
// 添加一个学生
func addStudent() {
var (
id int64
name string
)
fmt.Print("请输入您的学号:")
fmt.Scanln(&id)
fmt.Print("请输入您的姓名:")
fmt.Scanln(&name)
new := newStudent(id, name)
allStu[id] = new
}
// 删除一个学生
func delStudent() {
fmt.Print("请输入想要删除的学号:")
var (
id int64
)
fmt.Scanln(&id)
delete(allStu, id)
}
func main() {
allStu = make(map[int64]*student, 50)
for {
fmt.Println("欢迎来到学生管理系统!")
fmt.Println(`
1.查看所有学生信息
2.添加一个学生
3.删除一个学生
4.退出系统
`)
fmt.Print("请问你要运行什么功能!请输入指定数字:")
var selectID int64
fmt.Scanln(&selectID)
switch selectID {
case 1:
allStudent()
case 2:
addStudent()
case 3:
delStudent()
case 4:
os.Exit(1)
default:
fmt.Println("没有这选项,要退出请按4")
}
}
}
- 要不是代码太长 了,我肯定上图片的,啊哈哈哈哈哈
- 当然啦,这只是一个函数版本,我们学了方法满,当然可以改写成方法版本
- 这玩意很少用到,大多是用在匿名嵌套结构体里面,
- 当有两个结构体有了重复的字段的时候,我们可以将它抽取出来
- 例如:人类里面有省和城市,公司类里面也有省和城市
type address struct {
province string
city string
}
type person struct {
name string
age int
address
}
type company struct {
name string
address
}
- 先三个结构体,地区包装在address里面
- 结果呢就是一样的,只是这样方便一点。
- json作为现在最流行的传输数据的格式,当然要会转啦
- 直接上图
- 值得注意的是两点,
- 第一点: 首字母必须大写,前面也有说过,只有大写才能进行一个外部包的暴露,才能被调用。
- 第二点:json转完之后肯定是要继续全部小写的,这里可以用··这个符号来,就是感叹号左边那个东东。然后声明一个转了之后的别名,还能设置数据库的,和配置文件的别名哦
- 然后我们再看看反序列化
// 反序列化
s := `{"name":"小阿吉","age":17}`
var p2 person
json.Unmarshal([]byte(s), &p2)
fmt.Printf("%#vn", p2)
// 输出效果: main.person{Name:"小阿吉", Age:17}
- 这个还是没有问题的,就一个地方注意点就好啦。
- 在传值的时候,要进行传指针哦,不然修改的就是副本的值哦。原来的数据就不会发生改变了。传指针 传指针 传指针 传指针
今天就到这里把,晚上继续。。。。



