整数区间的交集和差集样例:
[1,5] + [6,10] = [1,10]
[1,100] - [10,20] = [1,9] + [21,100]
如果让你设计一个程序,能够计算整数区间的合集、交集、差集,你会怎么设计?
我会默默想想难度,然后去github上找找有没有可复用的开源代码。
go-intervals简介
go-intervals是一个用于在一维区间(例如时间范围)上执行集合操作的库,正好能满足我的整数区间计算需求。github地址为:https://github.com/google/go-intervals/
选用原因
之所以选择go-intervals有三个方面的考虑:
-
背靠谷歌金字招牌,足够让我相信代码质量 -
完整的测试用例 -
代码开源且易懂
代码剖析
go-intervals库能对多种一维区间集合进行操作,如时间、整数等;也能支持多种开闭区间,如左开右闭、左闭右开、左闭右闭等。代码是如何进行设计的呢?难道作者在代码内部实现了所有细节?
依赖倒转原则(DIP):高层模块不要依赖低层模块。高层模块和低层模块应该通过抽象(abstractions)来互相依赖。除此之外,抽象(abstractions)不要依赖具体实现细节(details),具体实现细节(details)依赖抽象(abstractions)。具体内容在Go设计模式(3)-设计原则有讲述。
思路:多个区间构成一个集合,区间是集合的基本单位。集合的交差并操作本质上是区间的交差并操作。
结合上面两点,作者的实现方式是将区间接口化。go-intervals只负责将在框架层面将两个集合的区间,两两进行交并差操作,交并差的实现逻辑由调用者自己实现。
type Interval interface {
Intersect(Interval) Interval
Before(Interval) bool
IsZero() bool
Bisect(x Interval) (Interval, Interval)
Adjoin(Interval) Interval
Encompass(Interval) Interval
}
实现
调用者想实现哪种区间、哪种开闭方式,只需要实现自己的Interval即可。我需要实现整数、左闭右闭区间的并集、差集操作。
左闭右开区间
在代码的测试用例中,作者给出了整数区间,左闭右开的实现:
type span struct {
min, max int
}
func cast(i Interval) *span {
x, ok := i.(*span)
if !ok {
panic(fmt.Errorf("interval must be an span: %v", i))
}
return x
}
func zero() *span {
return &span{}
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func (s *span) String() string {
return fmt.Sprintf("[%d, %d)", s.min, s.max)
}
func (s *span) Equal(t *span) bool {
return s.min == t.min && s.max == t.max
}
func (s *span) Intersect(tInt Interval) Interval {
t := cast(tInt)
result := &span{
max(s.min, t.min),
min(s.max, t.max),
}
if result.min < result.max {
return result
}
return zero()
}
func (s *span) Before(tInt Interval) bool {
t := cast(tInt)
return s.max <= t.min
}
func (s *span) IsZero() bool {
return s.min == 0 && s.max == 0
}
func (s *span) Bisect(tInt Interval) (Interval, Interval) {
intersection := cast(s.Intersect(tInt))
if intersection.IsZero() {
if s.Before(tInt) {
return s, zero()
}
return zero(), s
}
maybeZero := func(min, max int) *span {
if min == max {
return zero()
}
return &span{min, max}
}
return maybeZero(s.min, intersection.min), maybeZero(intersection.max, s.max)
}
func (s *span) Adjoin(tInt Interval) Interval {
t := cast(tInt)
if s.max == t.min {
return &span{s.min, t.max}
}
if t.max == s.min {
return &span{t.min, s.max}
}
return zero()
}
func (s *span) Encompass(tInt Interval) Interval {
t := cast(tInt)
return &span{min(s.min, t.min), max(s.max, t.max)}
}
左闭右闭区间
既然作者提供的不满足需求,就需要自己进行修改。参考左闭右开代码修改为左闭右闭代码,目前唯一的缺点是如果构建集合的区间有重叠会panic,重叠问题可以在业务层进行检查,倒也没什么问题。
type span struct {
min, max int64
}
func cast(i intervalset.Interval) *span {
x, ok := i.(*span)
if !ok {
panic(fmt.Errorf("interval must be an span: %v", i))
}
return x
}
func zero() *span {
return &span{}
}
func min(a, b int64) int64 {
if a < b {
return a
}
return b
}
func max(a, b int64) int64 {
if a > b {
return a
}
return b
}
func (s *span) String() string {
return fmt.Sprintf("[%d, %d]", s.min, s.max)
}
func (s *span) Equal(t *span) bool {
return s.min == t.min && s.max == t.max
}
func (s *span) Before(tInt intervalset.Interval) bool {
t := cast(tInt)
return s.max < t.min
}
func (s *span) IsZero() bool {
return s.min == 0 && s.max == 0
}
func (s *span) Intersect(tInt intervalset.Interval) intervalset.Interval {
t := cast(tInt)
result := &span{
max(s.min, t.min),
min(s.max, t.max),
}
if result.min <= result.max {
return result
}
return zero()
}
func (s *span) Adjoin(tInt intervalset.Interval) intervalset.Interval {
t := cast(tInt)
if s.max == t.min || s.max == t.min-1 {
return &span{s.min, t.max}
}
if t.max == s.min || t.max == s.min-1 {
return &span{t.min, s.max}
}
return zero()
}
func (s *span) Bisect(tInt intervalset.Interval) (intervalset.Interval, intervalset.Interval) {
intersection := cast(s.Intersect(tInt))
if intersection.IsZero() {
if s.Before(tInt) {
return s, zero()
}
return zero(), s
}
maybeZero := func(min, max int64) *span {
if min > max {
return zero()
}
return &span{min, max}
}
return maybeZero(s.min, intersection.min-1), maybeZero(intersection.max+1, s.max)
}
func (s *span) Encompass(tInt intervalset.Interval) intervalset.Interval {
t := cast(tInt)
return &span{min(s.min, t.min), max(s.max, t.max)}
}
测试
检验自己代码是否有问题有什么方法?至少有两点,一是代码review,二是单元测试。对于这种引入的第三方库、且自己实现部分逻辑,一定要做好单元测试,这是前人栽树后人乘凉的好事。
测试case整理如下:
[20,40]为指定区间,用其它区间和指定区间进行交、差操作。竖线表示左右区间值一样。
写了一晚上测试用例,初步测试没有问题。
package service
import (
"github.com/google/go-intervals/intervalset"
"reflect"
"testing"
)
func TestAddTest(t *testing.T) {
type args struct {
s1 *intervalset.Set
s2 *intervalset.Set
}
tests := []struct {
name string
args args
wantRes *intervalset.Set
}{
{
name: "empty + empty = empty",
args: args{
s1: intervalset.NewSet([]intervalset.Interval{}),
s2: intervalset.NewSet([]intervalset.Interval{}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{}),
},
{
name: "empty + [30,111] = [30, 111]",
args: args{
intervalset.NewSet([]intervalset.Interval{}),
intervalset.NewSet([]intervalset.Interval{&span{30, 111}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{30, 111}}),
},
{
name: "[20, 40] + empty = [20, 40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
{
name: "[20, 40] + [60,111]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{60, 111}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}, &span{60, 111}}),
},
{
name: "[20, 40] + [39,111]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{39, 111}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 111}}),
},
{
name: "[20, 40] + [40,111]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{40, 111}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 111}}),
},
{
name: "[20, 40] + [41,111]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{41, 111}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 111}}),
},
{
name: "[20, 40] + [30,111]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{30, 111}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 111}}),
},
{
name: " [20,40] + [25, 28] = [20,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{25, 28}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
{
name: " [20,40] + [10, 30] = [10,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{10, 30}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 40}}),
},
{
name: "[10, 19] + [20,40] = [10,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{10, 19}}),
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 40}}),
},
{
name: "[20,40] + [10, 20] = [10,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{10, 20}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 40}}),
},
{
name: "[20,40] + [10, 21] = [10,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{10, 21}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 40}}),
},
{
name: "[20,40] + [10, 15] = [10,15] [20,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{10, 15}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 15}, &span{20, 40}}),
},
{
name: "[20,40] + [10, 100] = [10,100]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{10, 100}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 100}}),
},
{
name: "[20,40] + [10, 10] = [10,10] [20 40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{10, 10}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 10}, &span{20, 40}}),
},
{
name: "[20,40] + [19, 19] = [19 40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{19, 19}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{19, 40}}),
},
{
name: "[20,40] + [20, 20] = [20 40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{20, 20}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
{
name: "[20,40] + [21, 21] = [20 40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{21, 21}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
{
name: "[20,40] + [25, 25] = [20 40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{25, 25}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
{
name: "[20,40] + [39, 39] = [20 40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{39, 39}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
{
name: "[20,40] + [40, 40] = [20 40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{40, 40}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
{
name: "[20,40] + [41, 41] = [20 41]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{41, 41}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 41}}),
},
{
name: "[20,40] + [50, 50] = [20 40] [50, 50] ",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{50, 50}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}, &span{50, 50}}),
},
{
name: "[20, 40] + [41,50]+ [50,60]+ [61,111] = [20,111]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}, &span{41, 50}}),
intervalset.NewSet([]intervalset.Interval{&span{50, 60}, &span{61, 111}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 111}}),
},
{
name: "[10, 19] + [20,20] = [10,20]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{10, 19}}),
intervalset.NewSet([]intervalset.Interval{&span{20, 20}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 20}}),
},
{
name: " [20,20] + [10, 19] = [10,20]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 20}}),
intervalset.NewSet([]intervalset.Interval{&span{10, 19}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 20}}),
},
{
name: "[10, 19] + [21,30] + [20,20] = [10,30]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{10, 19}, &span{21, 30}}),
intervalset.NewSet([]intervalset.Interval{&span{20, 20}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 30}}),
},
{
name: "[10, 15] + [20,20]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{10, 15}}),
intervalset.NewSet([]intervalset.Interval{&span{20, 20}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 15}, &span{20, 20}}),
},
{
name: " [20,20] + [10, 15]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 20}}),
intervalset.NewSet([]intervalset.Interval{&span{10, 15}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{10, 15}, &span{20, 20}}),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if gotRes := AddTest(tt.args.s1, tt.args.s2); !reflect.DeepEqual(gotRes.AllIntervals(), tt.wantRes.AllIntervals()) {
t.Errorf("Add() = %v, want %v", gotRes, tt.wantRes)
}
})
}
}
func TestSubTest(t *testing.T) {
type args struct {
s1 *intervalset.Set
s2 *intervalset.Set
}
tests := []struct {
name string
args args
wantRes *intervalset.Set
}{
{
name: "empty - empty = empty",
args: args{
s1: intervalset.NewSet([]intervalset.Interval{}),
s2: intervalset.NewSet([]intervalset.Interval{}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{}),
},
{
name: "empty - [30,111] = empty",
args: args{
intervalset.NewSet([]intervalset.Interval{}),
intervalset.NewSet([]intervalset.Interval{&span{30, 111}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{}),
},
{
name: "[30,111] - empty = [30,111]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{30, 111}}),
intervalset.NewSet([]intervalset.Interval{}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{30, 111}}),
},
{
name: "[20, 40] - [30,111] = [20,29]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{30, 111}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 29}}),
},
{
name: "[20, 40] - [41,111] = [20,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{41, 111}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
{
name: "[20, 40] - [40,111] = [20,39]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{40, 111}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 39}}),
},
{
name: "[20, 40] - [39,111] = [20,38]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{39, 111}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 38}}),
},
{
name: "[20, 40] - [25,28] = [20,24] [29,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{25, 28}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 24}, &span{29, 40}}),
},
{
name: "[20, 40] - [15,28] = [29,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{15, 28}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{29, 40}}),
},
{
name: "[20, 40] - [15,20] = [21,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{15, 20}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{21, 40}}),
},
{
name: "[20, 40] - [15,21] = [22,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{15, 21}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{22, 40}}),
},
{
name: "[20, 40] - [15,19] = [20,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{15, 19}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
{
name: "[20, 40] - [10,15] = [20,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{10, 15}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
{
name: "[20, 40] - [5,5] = [20,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{5, 5}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
{
name: "[20, 40] - [20,20] = [21,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{20, 20}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{21, 40}}),
},
{
name: "[20, 40] - [25,25] = [20,24] [26,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{25, 25}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 24}, &span{26, 40}}),
},
{
name: "[20, 40] - [40,40] = [20,39]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{40, 40}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 39}}),
},
{
name: "[20, 40] - [45,45] = [20,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{45, 45}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
{
name: "[20, 40] - [19,19] = [20,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{19, 19}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
{
name: "[20, 40] - [21,21] = [20,20] [22,40] ",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{21, 21}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 20}, &span{22, 40}}),
},
{
name: "[20, 40] - [39,39] = [20,38] [40, 40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{39, 39}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 38}, &span{40, 40}}),
},
{
name: "[20, 40] - [41,41] = [20,40]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{41, 41}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
{
name: "[20, 40] - [11,41] = []",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
intervalset.NewSet([]intervalset.Interval{&span{11, 41}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{}),
},
{
name: " [11,41] - [20, 40] = [11,19] [41 41]",
args: args{
intervalset.NewSet([]intervalset.Interval{&span{11, 41}}),
intervalset.NewSet([]intervalset.Interval{&span{20, 40}}),
},
wantRes: intervalset.NewSet([]intervalset.Interval{&span{11, 19}, &span{41, 41}}),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := SubTest(tt.args.s1, tt.args.s2); !reflect.DeepEqual(got.AllIntervals(), tt.wantRes.AllIntervals()) {
t.Errorf("Sub() = %v, want %v", got, tt.wantRes)
}
})
}
}
总结
很多时候真的不需要重复造轮子,而且也难说自己造的比别人的好,合理合法利用资源、按时完成任务有时候更加重要。写代码是谨小慎微的事情,单元测试必不可少。不但能帮助自己理清思路、发现问题,也能防止后来人改出错误。
最后
大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)
我的个人博客为:https://shidawuhen.github.io/
往期文章回顾:
-
设计模式 -
招聘 -
思考 -
存储 -
算法系列 -
读书笔记 -
小工具 -
架构 -
网络 -
Go语言
|