typeScript的一个坑

缘起

最近找了个兼职,写了一段node的typescript代码,虽然上次写node还是5年前,但因为使用的框架是midway,写的过程中,几乎没有碰到bug,很自然的感觉,就是spring的那一套,面向对象,依赖注入等,写web还是很方便的。

不过也由于这几年天天看和写java代码,写的时候,很容易就按照面向对象写起来,一切都是class,class的方法等,所以这也是bug的由来。

问题来龙去脉

业务bug简单描述

一个学校有n个老师,每个老师一门课程,期末的时候,老师会给学生打分,学生同时也是一个用户。

问题:在打分的过程中,为了方便,对学生对象list转换成了map,然后每个老师都会对学生的分数进行统计,然后再把统计结果返回给学生,这样就会导致学生的分数被覆盖。发现学生的成绩到最后都是一个老师打的。

复现代码

class User {
    Name: string;
    Age: number;
}

class Student extends User {
    Grade: number;
}

class Teacher {
    Name: string;
    Class: string;
    Students: Student[];
}

const user1 = new User();
user1.Name = 'John';
user1.Age = 30;


const user2 = new User();
user2.Name = 'Jane';
user2.Age = 25;



const users = [user1, user2];

const teacher = new Teacher();
teacher.Name = 'Bob';
teacher.Class = '1A';

const teacher2 = new Teacher();
teacher2.Name = 'Alice';
teacher2.Class = '1B';

const teachers = [teacher, teacher2];

const userMap = users.reduce((acc, cur) => {
    acc[cur.Name] = cur;
    return acc;
  }, {});

const gradeTeacher = new Array<Teacher>();

teachers.forEach(teacher => {
    const students = new Array<Student>();
    const teacherName = teacher.Name;

    Object.entries(userMap).forEach(([key, value]) => {

        let student = new Student();
        student = userMap[key];
        if (teacherName === 'Bob') {
          student.Grade = 100;
        } else {
            student.Grade = 50;
        }
        students.push(student);

    });
    teacher.Students = students;
    gradeTeacher.push(teacher);
});


for (const teacher of gradeTeacher) {
    console.log(teacher); 
}

理论期望的结果

Teacher {
  Name: 'Bob',
  Class: '1A',
  Students: [
    User { Name: 'John', Age: 30, Grade: 100 },
    User { Name: 'Jane', Age: 25, Grade: 100 }
  ]
}
Teacher {
  Name: 'Alice',
  Class: '1B',
  Students: [
    User { Name: 'John', Age: 30, Grade: 50 },
    User { Name: 'Jane', Age: 25, Grade: 50 }
  ]
}

实际结果

Teacher {
  Name: 'Bob',
  Class: '1A',
  Students: [
    User { Name: 'John', Age: 30, Grade: 50 },
    User { Name: 'Jane', Age: 25, Grade: 50 }
  ]
}
Teacher {
  Name: 'Alice',
  Class: '1B',
  Students: [
    User { Name: 'John', Age: 30, Grade: 50 },
    User { Name: 'Jane', Age: 25, Grade: 50 }
  ]
}

why?

可以看到,user 被循环了两次,而且每次都是user1,user2,这样就导致了学生的分数被覆盖。

Read more →

Go slice的一个坑

问题

最近在刷leedcode,求二叉树的路径和,给定一个二叉树,求所有符合条件的路径。原题见 113. Path Sum II

这道题需要遍历所有的节点,并且记录遍历路径上的节点,可以使用回溯法,深度优先的方法。

不过最近用习惯了广度优先的方法,把二叉树变成一个有序的队列,这种思想很好玩,把多个选择的,需要遍历的变成一个有序的来进行遍历即可,就是一个万能模板。

下面贴下代码

var result [][]int

var ch = make(chan *TreeNode, 100)
var sumChan = make(chan int, 100)
var nodes = make(chan []int, 100)

for len(ch) > 0 {
    for i := 0; i < len(ch); i++ {
        //获取当前节点
        cur := <-ch
        //获取父节点的总和
        parentSum := <-sumChan
        //获取父节点的所有路径节点序列
        parents := <-nodes
        //当前节点的总和
        curSum := parentSum + cur.Val
        //当前节点的序列
        curNodes := append(parents, cur.Val)

        if cur.Left == nil && cur.Right == nil {
            if curSum == targetSum {
                // 添加当前节点序列到结果集
                result = append(result, curNodes)
            }
        } else {
            if cur.Left != nil {
                ch <- cur.Left
                sumChan <- cur.Val + parentSum
                nodes <-  curNodes
            }
            if cur.Right != nil {
                ch <- cur.Right
                sumChan <- cur.Val + parentSum
                nodes <- curNodes
            }
        }

    }
}

大家细读一下,不知道有没有看出来哪里不对,我先贴一下结果 test case

Read more →