下文转自stormzhang微信公众号
最近是跳槽的高峰,很多人应该都在准备面试,我知识星球有球友问我面试需要注意什么事项,其实面试需要注意的事项你可以网上搜索一大堆,那些事项会对你的面试多少有点帮助,但不会起到决定性的作用,最重要的还是自己要有实力,没有实力的话,任何注意事项都是白搭。
但是,今天我想给大家说下我面试时一定会问的一个问题:
你最擅长什么?
这不是说你业余擅长什么,而是在你的专业领域内你最擅长什么。
很多人一开始是懵的,想想自己各方面都还可以,但实在想不到自己最擅长什么地方,其实,如果你面试的是高级工程师职位,这个点异常重要。
所谓的高级工程师,除了你的项目经验比较丰富,综合能力较强之外,他们一定有个自己擅长的点,比如拿 Android 来说,有人擅长动画、有人擅长音视频、有人擅长插件化、有人擅长性能优化、有人擅长架构等等等,这些领域不需要你每一门都多么精通,毕竟人的精力是有限的,但是一定要在某一领域花时间深入的研究过,甚至还有自己的理解,让这个点形成自己的核心竞争力,才是别人眼里的高级人才。
当然,有人可能会误解,这里稍作解释下,并不是说只会一个点就够了,而是说在其他领域都还可以的情况下,有一个点是最擅长最突出的,这种人才才是稀缺的,也是不可替代的。
我前后面过很多人,哪怕工作六七年的人,也有从来没注意过这个问题。
前段时间就有人在微信上问我,说自己做开发四五年了,但是总感觉自己遇到了瓶颈,他还是在国内某互联网大公司工作的人,按理说已经比大部分人要优秀的多了。
我当时就问了他这么一个问题,他想了半天没有答案,自我感觉就是各方面能力都还行,说的好听点是全面发展,然而也意味着没有自己的核心竞争力,我给他的建议就是,想走技术路线的话,就一定要针对某一领域去深入研究,别以为某一领域看起来很简单,然而任何一个方向想深入研究下去,都需要花费大量精力的。
所以,不管你是为了面试也好,还是以后你想让自己更进一步发展,不妨问问自己这个问题,如果没有答案,现在开始为时不晚。
今天跑去腾讯面试了,就被问了,直接傻了。就是上面典型的没有自己的核心竞争力。于是回来了就想了下,如果自己选一个方向,那么要选什么呢?
C 语言, Nginx
C++ 语言, 泛型编程 STL, Qt 图形库
Golang 语言, Docker 容器, Kubernetes, Beego
网络技术, ARP, TCP, UDP, HTTP, WebSocket, DNS
Linux 系统
Windows 系统
数据库, MySQL, Oracle, postgreSQL, SQLServer
No-sql, redis,
算法
全栈开发
安全加密
设计模式
编辑器, vim, vscode
版本控制, git, svn
人的精力是有限的,只能从这么多的东西中选择一个深入研究。
via: https://blog.golang.org/slices
via: https://golang.org/doc/effective_go.html
via: https://github.com/golang/go/wiki/CodeReviewComments
via: https://www.calhoun.io/6-tips-for-using-strings-in-go/
自从引入了内置的 append
后,container/vector
包(在 Go 1 中已经被移除)的大部分功能都可以使用 append
和 copy
来代替了。
这里是 vector 方法和它们的类似切片的操作:
AppendVector
a = append(a, b...)
拷贝
b = make([]T, len(a))
copy(b, a)
// or
b = append([]T(nil), a...)
剪切
a = append(a[:i], a[j:]...)
删除
a = append(a[:i], a[i+1:]...)
// or
a = a[:i+copy(a[i:], a[i+1:])]
删除而不保留顺序
a[i] = a[len(a)-1]
a = a[:len(a)-1]
注意如果元素的类型是一个指针或一个带有指针字段的结构体,这些指针字段需要被垃圾回收,上述 Cut
和 Delete
的实现有一个潜在的内存泄漏问题:一些带有值的元素仍然被切片 a
引用,因此不能被垃圾回收。以下代码可以解决此问题:
剪切
copy(a[i:], a[j:])
for k, n := len(a)-j+i, len(a); k < n; k++ {
a[k] = nil // or the zero value of T
}
a = a[:len(a)-j+i]
删除
copy(a[i:], a[i+1:])
a[len(a)-1] = nil // or the zero value of T
a = a[:len(a)-1]
删除而不保留顺序
a[i] = a[len(a)-1]
a[len(a)-1] = nil
a = a[:len(a)-1]
Expand
a = append(a[:i], append(make([]T, j), a[i:]...)...)
Extend
a = append(a, make([]T, j)...)
插入
a = append(a[:i], append([]T{x}, a[i:]...)...)
注:第二个 append 创建一个带有其自己的底层存储的新切片,并将 a[i:]
中的元素复制到该切片,然后将这些元素复制回切片 a
(通过第一个 append
)。通过使用另一种方式可以避免创建新的切片(从而产生内存垃圾)和两次拷贝:
插入
s = append(s, 0)
copy(s[i+1:], s[i:])
s[i] = x
InsertVector
a = append(a[:i], append(b, a[i:]...)...)
Pop/Shift
x, a = a[0], a[1:]
Pop Back
x, a = a[len(a)-1], a[:len(a)-1]
Push
a = append(a, x)
Push Front/Unshift
a = append([]T{x}, a...)
过滤时不需要而外分配空间
这个技巧基于一个事实:即过滤切片与原始切片共享相同的底层数组和容量,因此该底层数组将被重用于过滤切片。当然,原始内容已被修改。
b := a[:0]
for _, x := range a {
if f(x) {
b = append(b, x)
}
}
反转数组
用相同的元素替换切片的内容,但以相反的顺序替换:
for i := len(a)/2-1; i >= 0; i-- {
opp := len(a)-1-i
a[i], a[opp] = a[opp], a[i]
}
同样的事情,除了用了两个索引:
for left, right := 0, len(a)-1; left < right; left, right = left+1, right-1 {
a[left], a[right] = a[right], a[left]
}
洗牌算法
Fisher–Yates 算法
for i := len(a) - 1; i > 0; i-- {
j := rand.Intn(i + 1)
a[i], a[j] = a[j], a[i]
}
via: https://github.com/golang/go/wiki/SliceTricks