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]
}
运行结果:
练习题:使用“面向对象”的思维方式编写一个学生信息管理系统。
- 学生有id、姓名、年龄、分数等信息
- 程序提供展示学生列表、添加学生、编辑学生信息、删除学生等功能。
代码:
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语言基础之结构体