struct面试题——推测下述代码的运行结果

type student struct {
	name string
	age  int
}
func main() {
	m := make(map[string]*student)
	stus := []student{
		{name: "小王子", age: 18},
		{name: "娜扎", age: 23},
		{name: "大王八", age: 9000},
	}
	for _, stu := range stus {
		m[stu.name] = &stu
	}
	for k, v := range m {
		fmt.Println(k, "=>", v.name)
	}
}

不管你有没有运行分析这段代码,都请仔细阅读代码后再看运行结果:
在这里插入图片描述
入门新手大多数会预测结果是
小王子=>小王子
娜扎=>娜扎
大王八=>大王八
先说明这段代码的意思:
(1)初始化一个map m:key为string,value为student的指针类型。定义一个student类型的数组stus并初始化添加三个学生:小王子、娜扎、大王八;
(2)用for range 循环给map m添加三个键小王子、娜扎和大王八,分别给其赋值数组中三个元素的地址;
(3)用for range 循环打印每个键值对value(地址)指向的内存(是个键值对)name的值。
下面添加几行输出给大家解释结果:
在这里插入图片描述
在第一个for range 循环中,给map m的每个value赋的值是同一个,我们去索引这个值对应的内容发现这个地址是“{大王八 9000}”对应的地址。真相大白了,弄了半天操作的全是大王八这个学生的数据。
因为for range创建了每个元素的副本,而不是直接返回每个元素的引用,如果使用该值变量的地址作为指向每个元素的指针,就会导致错误,在迭代时,返回的变量是一个迭代过程中根据切片依次赋值的新变量,所以值的地址总是相同的,导致结果不如预期。(这还是值传递的问题,可看上篇博客帮助理解)
不出意料地,将第一个for range 循环改为以下代码后:

	for i := 0; i < len(stus); i++{
		m[stus[i].name] = &stus[i]
	}

运行结果:
在这里插入图片描述
练习题:使用“面向对象”的思维方式编写一个学生信息管理系统。

  1. 学生有id、姓名、年龄、分数等信息
  2. 程序提供展示学生列表、添加学生、编辑学生信息、删除学生等功能。
    代码:
package main

import (
	"fmt"
)

type Student struct {
	id int
	name string
	age int8
	score float32
}

var (
	stuList[] Student
	studNum = 0                                      // 用于生成id
)

func newStu (id int, name string, age int8, score float32) *Student {  // 构造方法
	return &Student{
		id: id,
		name: name,
		age: age,
		score: score,
	}
}

func getStuList() []Student{  // 返回学生列表, 用于查询
	return stuList
}

func addStu()  {             // 添加学生
	var id = studNum
	studNum += 1           					    // id随着学生数量递增
	var name string
	var age int8
	var score float32
	fmt.Print("请输入学生姓名:")
	_, err := fmt.Scan(&name)
	fmt.Print("请输入学生年龄:")
	_, err = fmt.Scan(&age)
	fmt.Print("请输入学生成绩:")
	_, err = fmt.Scan(&score)
	if err != nil {
		fmt.Println("输入错误!!ERROR:", err)
	}
	newStu(id, name, age, score)
	stuList = append(stuList, *newStu(id, name, age, score))
}

func deleteStu() {       // 输入学生id进行删除
	var i int
	fmt.Println("请输入学生id:")
	_, err := fmt.Scan(&i)
	if err != nil {
		fmt.Println("输入错误!!ERROR:", err)
	}
	for _, v := range stuList {
		if v.id == i {
			stuList = append(stuList[:i], stuList[i+1:]...)
		}
	}
}

func editInfo() {      // 输入学生id对其进行编辑、修改
	var i int
	fmt.Println("请输入学生id:")
	_, err := fmt.Scan(&i)
	if err != nil {
		fmt.Println("输入错误!!ERROR:", err)
	}
	for _, v := range stuList {
		if v.id == i {
			fmt.Print("请输入学生姓名:")
			_, err := fmt.Scan(&stuList[i].name)
			fmt.Print("请输入学生年龄:")
			_, err = fmt.Scan(&stuList[i].age)
			fmt.Print("请输入学生成绩:")
			_, err = fmt.Scan(&stuList[i].score)
			if err != nil {
				fmt.Println("输入错误!!ERROR:", err)
			}
		}
	}
}

func main()  {
	for {
		fmt.Println("要执行的操作:")
		fmt.Print("1. 添加  2.查看  3.删除  4.修改\n")
		var do int8
		_, err := fmt.Scan(&do)
		if err != nil {
			fmt.Println("输入有误!")
		}
		switch do {
		case 1:
			addStu()
		case 2:
			fmt.Println(getStuList())
		case 3:
			deleteStu()
		case 4:
			editInfo()
		default:
			fmt.Println("输入有误!")
		}
	}
}

运行截图:
在这里插入图片描述
在这里插入图片描述
由于初学golang很怕这道习题会用很多时间,但是考虑到这将是以后写后端的基础——“增删改查”后,我还是用了两个小时写了这道题。目前程序对于无效输入的判断还不完全,希望大家多多交流指正。
题目出处:李文周的博客——Go语言基础之结构体