原则
快捷键不能过多
快捷键不能过多,一个 ide 就有许多快捷键,再加上浏览器,终端等等,快捷键如此之多,而且快捷键与功能之间并没有关系,也就是说,你只能靠大量练习形成肌肉记忆,这并不是一个高效的学习方式。
一般来说,对于一个应用来说,记忆 20,30 个都是很多的了,最主要的不是把快捷键记住,而是你要知道你在干什么,你要干什么。
不要只死记快捷键,要理解它的意义
比如我曾经无数次搜索 Goland 的快捷键表,可是最后记忆的还是那么几个,几乎没有增加,像什么 alt+shift,实现接口的 ctrl+i ,我看见过许多次,可是我仍然无法记住。
现在看来,这种方式就是错误的,不应该去“记忆”,而是要先理解它是什么意义,然后在用的时候会想到有这么一个功能,然后再去用。
使用工具帮助记忆
自然我们会时常忘记对应的快捷键是什么,但这其实反而并不是太大的问题。为了解决这个问题,我们有两个方法。一就是写 cheat-list,要用的时候直接查,而就是使用搜索功能,直接搜索对应的快捷键。而在 Goland 中,搜索功能就是特殊的几个快捷键,如搜索 action, file, type 等。
这里扩展一下 i3 桌面,也是这么个道理,把多余的画面去掉,即可以强迫我们使用键盘,也能强迫我们使用搜索功能。无鼠标编程显然效率是灰常高的,当然也比时常要移动手去使用鼠标要舒适,还有 b 格加成。然后同时使用搜索功能也有几个好处。一是强化功能的印象,搜索时,其名字往往代表其功能,故在搜索时能表明知道自己在做什么,也能强化有这个功能的印象,许多功能并不是只有这个工具才有,这种强化思维也能迁移,会提高有意识提高效率的意识,会主动去寻找提高效率的方式,同时迁移工具时也会考虑这些。最后就是熟悉一下单词,比如我现在已经能熟练拼写 settings, plugins, keymap, background等等。。这能加大我们接触英语的可能性,因为这是我们主动的,而不是被动的。
- 不要大幅度的修改初始快捷键
自由度过高,大幅度的修改快捷键有一些坏处,如难以迁移,从迁移环境时比较麻烦,别人难以使用,有时会有牵一发而动全身的效果,改一个快捷键可能会造成后续大量的快捷键冲突,自定义的不符合人体工程学,上手成本过高等等。我曾经在 Goland 中使用 vim 插件,给 action 自定义了大量的快捷键,而且不同模式移动光标方法也不同,我使用的键盘也是可编程键盘,然后折腾了许久,最后对这一套我自己也不熟悉,编程效率直线下贱,而代码却未敲几行,甚至我还尝试过不同的键盘布局,最后我想到有时会使用其他环境而放弃了。总之,一切皆有度。
移动光标
基础
上 下 左 右
移动到行首/尾
向上/下翻页
这几个都是非常高频的键,但是如果是标准键位,使用这几个键都有大幅度的手部移动,这是非常难受的。我使用的是 66 布局,可以硬件编程。在 Space 左边有一个 fn 键,我的设置是
fn + h/j/k/l 左/下/上/右
fn + i/o home/end
fn + ; / page up/ page down
左手大拇指按住 fn,右书按字母,这样不用移动手,习惯了后效率还是挺高的。
- Ctrl+m
这也是一个常用的键,有时候我们的写着写着,光标就到屏幕底部了,继续写时观看很不方便,这时我们就可以使用这个键,屏幕会滑动到光标所在处,即屏幕以光标为中心。
Ctrl+左/右 移动到上/下一个单词
Ctrl+home/end 移动到文件首/尾处
Ctrl+上/下 屏幕滑动但光标不动
跳转
- ctrl+B
这是一个非常常用的键,使用这个会跳转到变量的定义处,如我们要查看某个函数的源码实现时,对着实例使用即可
- 插件: acejump-lite
当我们要在屏幕上跳转时,如光标在屏幕低,要跳转到屏幕顶某处,就可以使用这个插件,我自定义为 fn+m, 然后输入跳转的目标字符
- Ctrl+e
这是一个非常常用的键
当我们要跳转到最近的文件时,可以使用这个键,然后移动到目标文件
当要跳转到某个文件时,也可以输入这个键,先使用这个键,然后输入文件名即可,这个类似使用 Ctrl+shift+N 查找文件
当我们要进入一些弹窗时,如要进入 run 窗口, terminal 窗口,enven log 窗口时,或者一些插件的窗口,如 translate 插件的 word book (生词本) 窗口,可以使用这个键再搜索名字
- Ctrl+Shift+A
这也是一个非常常用的键,我们可以用这个键做许多事,这个键用来使用 action,action 是 goland 中许多操作都有的一个东西。
如我们要打开 设置,就可以使用键后,输入 settings 即可
如我们要打开 插件,输入 plugins, 要把主菜单关掉,可以输入 main ,第一个就是,或者我们要删除文件,可以对着文件输入 delete, 要新建文件,可以输入 go,要新建项目,可以输入 project ,要 运行代码,可以输入 run 等等,总之这个键可以代替大多数需要移动鼠标才能做的,要达到无鼠标编程,这个键需要熟练使用。
- Ctrl+ 2⁄3
在编程中,我们经常会遇到 error,waring 等,我们想要检查文件有没有这些时,就可以使用这个键,在 goland 中原来的键是 F2/shift+F2, 即查询下/上一个 error,但是我键盘布局不方便,所以设置了一下
想提高程序健壮性,即检查 error, waing 等时,就可以使用这个键,在 goland 中一般 error 是红色下划线,警告是黄色下划线,还有其他的提示等,总之在提示处有值得改进的地方
想要快速跳转到 error 处,有时候我们要修改 error 时,使用 光标移动显然有些低效,这是我们可以直接用这个键,就可以直接跳转到 error 处
- ctrl+shfit
返回刚打开的 tab
enter 新建下一行并移动到下一行, 改变此行
ctrl+enter 拆分此行,鼠标不动,在行尾使用,可新建下一行并鼠标不动
shift+enter 新建下一行并移动到下一行(不改变此行)
ctrl+alt+enter 新建上一行并到上一行
Ctrl+N fing type
Ctrl+Shift+N 查找 file Ctrl+Alt+Shift+N 查找 func
Ctrl+[ 跳转到函数大括号开始
Ctrl+] 跳转到函数大括号结束
提示
- Ctrl+1 显示 error
- Ctrl+p 显示参数 parameter info
- Ctrl+Q show documentation, 用来显示返回值比较方便
其他
- fn+s
这三个设置为一个快捷键比较方便,我使用的是硬件编程,也可是试试 vim 插件,我还没有找到其他方法能够这样设置
Ctrl+Alt+L 格式化代码 Ctrl+Alt+O 优化导入的类和包 Ctrl+S save
- Alt+1
打开侧边栏
- Shift+F6
rename 所有的文件,类名,函数名,属性名都可以重命名,使用 Shift+F6 重命名,所有使用过这个名称的地方都会跟着改变
- Ctrl+R
run
- Ctrl+w
我们经常会修改代码,删除代码,那么就必然需要选中代码,这个快捷键就是用来选中代码的,连续使用会以此选中更多的代码。
比如我们要修改字符串
fmt.Println("Sdfmsdf")
光标在 “” 中,那么我们使用一次 Ctrl+w 就会选中 “” 中的字符,就可以直接给修改或删除了,我们可以继续按,则会以此加上双引号,以此加上括号,以此选中整个语句。
如果我们要删除某个函数,可以对着函数名或直接在函数中多按几次 Ctrl+w, 就会选中整个函数代码块了,当然直接对着函数名按的次数少一些。
如果我们按快了,也可以按 Ctrl+shift+w 来撤销上一次选中。
Ctrl+/ 行注释
Ctrl+shift+/ 快注释
Ctrl+k git add and commit Ctrk+shift+k git push
Ctrl+shift+space 智能提示
Ctrl+shift+f find in path Ctrl+shift+r replace in path
Alt+j 选中相同的变量
Ctrl+shift+c 复制当前的文件的路径
Ctrl+d 重复当前行或选中文本
Ctrl+x 剪切当前行
Ctrl+c 双击复制当前行
Ctrl+y 删除当前行
ctrl+上:Clone Caret Above,多行选择
ctrl+下:Clone Caret Below
插件
- translate 插件
Ctrl+shift+y 取词翻译
Ctrl+shift+o 弹出翻译弹窗
- acejump-lite
fn+m 字符跳转
代码生成
最特殊的键 alt+enter
此 action name 是 show context actions
这个键的作用可以在 Settings>Editor>Intensions>go 中查看
最常用的几个就是 struct 相关
和调用函数
以及add comment
了
struct 相关
- File all fields
使用 struct 时,补全 其所有 fileds,只限于第一层,若 fileds 有 struct ,则不 fill 子 struct, 在 使用的 struct 里使用即可
Before
type Address struct { Street string; City string }
type Person struct { Name string; Location Address }
_ = Person{}
After
type Address struct { Street string; City string }
type Person struct { Name string; Location Address }
_ = Persona{
Name: "",
Location: Address{},
}
- File all fileds recursively
使用 struct 时,补全 其所有 fileds,只限于第一层,若 fileds 有 struct ,则递归的 fill 所有 struct, 在 使用的 struct 里使用即可
Before
type Address struct { Street string; City string }
type Person struct { Name string; Location Address }
_ = Person{}
After
type Address struct { Street string; City string }
type Person struct { Name string; Location Address }
_ = Persona{
Name: "",
Location: Address{
Street: "",
City: "",
},
}
- file fileds
使用 struct, 选择一个 filed 补全, 在使用的 struct 里使用即可
Before
type Address struct { Street string; City string }
type Person struct { Name string; Location Address }
_ = Person{}
After
type Address struct { Street string; City string }
type Person struct { Name string; Location Address }
_ = Persona{
Name: "",
}
- Generate constructor
给 struct 生成 new 方法,在 struct 的声明处使用
Before
type Person struct {
name string
age int
}
After
type Person struct {
name string
age int
}
func NewPerson(name string, age int) *Person {
return &Person{name: name, age: age}
}
- Generate getter
给 struct filed 生成 getter 方法,在 struct 声明处,对着要生成的特定 file 即可
Before
type Person struct {
name string
}
After
type Person struct {
name string
}
func (p *Person) Name() string {
return p.name
}
- Generate setter
给 struct filed 生成 setter 方法,在 struct 声明处,对着要生成的特定 file 即可
Before
type Person struct {
name string
}
After
type Person struct {
name string
}
func (p *Person) SetName(name string) {
p.name = name
}
- Generate getter and setter
给 struct filed 生成 getter 和 setter 方法,在 struct 声明处,对着要生成的特定 file 即可
Before
type Person struct {
name string
}
After
type Person struct {
name string
}
func (p *Person) Name() string {
return p.name
}
func (p *Person) SetName(name string) {
p.name = name
}
- Implement interface
给结构体实现某接口,接口可以是自定义的,也可以是已有的。也就是给结构体生成接口含有的所有方法。这个功能有快捷键 Ctrl+i, 对着结构体的声明处使用即可
Before
package main
type A struct {}
type B interface {
a1() int
a2() int
a3() int
}
After
package main
type A struct {}
func (*A) a1() int {
panic("implement me")
}
func (*A) a2() int {
panic("implement me")
}
func (*A) a3() int {
panic("implement me")
}
type B interface {
a1() int
a2() int
a3() int
}
- Move field assignment to struct initialization
使用了一个 struct, 然后又写了一个赋值语句,这个命令是把两个语句合成一个语句,在 初始化语句里使用即可
Before
s := S{}
s.foo = `bar`
After
s := S{foo: `bar`}
- Remove keys from struct literal
使用 struct 时,把 filed name 去掉,在使用 struct 时使用
Before
var _ = struct{int; string; slice []int}{string : "a", int : 2}
After
var _ = struct{int; string; slice []int}{2, "a", nil}
调用函数
- ignore explicitly
调用函数时,有时函数会报黄,会出现这个选项,这个选项有点类似 Introduce to local variable , 不过后者是快速生成返回值,这个则是用 _
占位符表示返回值
before
ioutil.WriteFile()
After
_ = ioutil.WriteFile()
- do not report this method/function anymore
调用函数时,有时函数会报黄,会出现这个选项, 使用这个后这个函数班会再变黄,至于为什么会变黄,我猜是 warning, 具体原因暂时未知
- Introduce to local variable
调用函数时,迅速生成赋值返回值变量,对着调用的函数名使用
Before
func Add(a int, b int) int {
return a + b
}
func main() {
Add(1, 2)
}
After
func Add(a int, b int) (int, error) {
return a + b, nil
}
func main() {
add, err := Add(1, 2)
}
- Rename _
调用函数后,把没有使用的赋值变量变为 _ , 对着没有使用的变量使用即可
Before
func Add(a int, b int) (int, error) {
return a + b, nil
}
func main() {
a, err := Add(1, 2)
}
After
func Add(a int, b int) (int, error) {
return a + b, nil
}
func main() {
_, err := Add(1, 2)
}
- Insert bank identifies to left side of assginment statement
调用函数时,若有多个返回值,而赋值的变量没有返回值多,那么对着变量使用后,会自动补全返回值个数
Before
func Add(a int, b int) (int, error) {
return a + b, nil
}
func main() {
a := Add(1, 2)
}
After
func Add(a int, b int) (int, error) {
return a + b, nil
}
func main() {
a, _ := Add(1, 2)
}
- Replace with “:”
调用函数时,若赋值的变量没有声明,那么对其使用就会直接声明后赋值
Before
func Add(a int, b int) (int, error) {
return a + b, nil
}
func main() {
a = Add(1, 2)
}
AAfter
func Add(a int, b int) (int, error) {
return a + b, nil
}
func main() {
a := Add(1, 2)
}
- Add missing return values
函数 return 返回值时,若个数不够,那么在 return 使用会自动增加返回值
Before
func Add(a int, b int) (int, error) {
return a + b
}
After
func Add(a int, b int) (int, error) {
return a + b, nil
}
- Remove 2nd result parameter from function
函数 return 返回值时,若个数不够, 或者调用函数时,赋值的变量比返回值少,使用后会把返回值减少到对应个数
Before
func Add(a int, b int) (int, error) {
return a + b, nil
}
func main() {
a := Add(1, 2)
}
After
func Add(a int, b int) int {
return a + b
}
func main() {
a := Add(1, 2)
}
或者
Before
func Add(a int, b int) (int, error) {
return a + b
}
After
func Add(a int, b int) int {
return a + b
}
声明变量
- Add parens to declaration
给单个变量声明时添加括号,在变量声明处使用
Before
var a string
After
var (
a string
)
这里说一下 import 时的情况,在 goland 中,只 import 了一个package,要加括号的话在 import 后直接打 ( 即可,goland 会自动把其放入括号中
- Remove parens from declaration
与 Add parens to delartion 相反,去除括号
Before
var (
a string
)
After
var a string
- Merge all declaration
给连续三个以上的变量声明划分为一组,空格隔开的不算,对着变量使用即可
Before
var a string
var b int
var c float32
var d bool
var e int
After
var a string
var (
b int
c float32
d bool
)
var e int
- split all declaration
与 Merge all declaration 相反,会把括号里的变量分开声明
Before
var (
a string
b int
c int
)
After
var a string
var b int
var c int
- merge declaration up
把这个变量和上一个声明的变量放在一个括号中,空格不影响
Before
var a string
var b int
After
var (
a string
b int
)
- merge declaration up via comma
把这个变量和上一个声明的变量放在一行,空格不影响
Before
var a int
var b int
After
var a, b int
- split declaration by comma
于 merge declaration up via comma 相反,把一行声明的变量变为多行声明
Before
var a, b int
After
var a int
var b int
- convert to short var declaration
把 var 变量的声明格式变为更短的 := 格式,在 var 变量声明处使用
Before
var x = 1
After
x := 1
- convert to var declaration
与 convert to short var declaration 相反,把 := 声明的变量变为 var 声明的格式,在 := 变量声明处使用
Before
x := 1
After
var x = 1
函数其他
- Add comment
在声明函数的地方,对着函数名可以生成此函数的注释
Before
package foo
func Foo() {
}
After
package foo
// Foo
func Foo() {
}
- add format string argument
在支持格式化的函数的参数里, 即 (“”) 的引号中使用。选择一个变量后,会自动生成相应的格式化输出。
如 int 类型 a, 输入 a 后会自动生成 %d, 而无需记忆对应的意义。
Before
func log(count int) {
fmt.Printf(`count is: `)
}
After
func log(count int) {
fmt.Printf(`count is: %d`, count)
}
- Expand signature types
在参数和返回值时,转换类型的写法, 在参数或返回值括号内使用即可
Before
func foo(s1, s2 string) (i1, i2 int) {
return 0, 1
}
After
func foo(s1 string, s2 string) (i1 int, i2 int) {
return 0, 1
}
- Reuse signature types
与上面的 Expand signature types 相反
Before
func bar(s1 string, s2 string) (i1 int, i2 int) {
return 0, 1
}
After
func bar(s1, s2 string) (i1, i2 int) {
return 0, 1
}
- Export
把私有 func, type, filed 变为公有的,在 func或 type 或 sturct 里的 filed 里使用即可
Before
func private() {}
After
func Private() {}
- Invert if
把 if- else 语句反过来,在 操作符 处使用即可
Before
a := 1
if a >= 2 {
fmt.Println("a >= 2")
} else {
fmt.Println("a < 2")
}
After
a := 1
if a < 2 {
fmt.Println("a < 2")
} else {
fmt.Println("a >= 2")
}
单词
- typo change to
对着拼错的单词使用,在对标识符命名,写注释什么的很方便
Before
blak
After
black
导包
- sync dependencies of
在 import 后添加想要拉的包 path, 任何使用这个 action, 可以直接拉包,类似 go get。
- Add dot import alias
在导的包前或使用的包名中使用,可以直接用包里的函数
Before
package main
import "fmt"
func main() {
fmt.Println("Hello World!")
}
After
package main
import . "fmt"
func main() {
Println("Hello World!")
}
- Remove dot import alias
和 Add dot import alias 相反,取消其效果,导的包前或使用的包名中使用
Before
package main
import . "fmt"
func main() {
Println("Hello World!")
}
After
package main
import "fmt"
func main() {
fmt.Println("Hello World!")
}
- Add import alias
这个同样在导的包前或使用的包名中使用,可以给包设置别名
Before
package main
import "fmt"
func main() {
fmt.Println("Hello World!")
}
After
package main
import fmtAlias "fmt"
func main() {
fmtAlias.Println("Hello World!")
}
操作表达式的改变
- flip binary operator
- negate expression
- negate expression recurisively
- negate topmostexpression
- negate topmostexpression recurisively
这几个都是不常用的(至少我没怎么用到)
生成测试代码 Ctrl+Shift+T
此 action name 是 go to test
这个键一共有 4 个功能
Test for functions
这个是最常用的,在函数内使用即可。
这个功能是生成函数测试。
go 中的测试文件需要在原有文件名后加上 _test, 测试函数需要在函数名前加上 Test ,参数也是特殊的。
如果手动生成的话比较麻烦且容易忘记,于是可以使用此快捷键。
如:
Before
db.go 中
func Hello {
fmt.Println("Hello World")
}
After
生成 db_test.go 文件
其中
func TestHello(t *testing.T) {
//...
}
Test for files
生成此 files 内的所有函数的 test
Test for package
生成此 package 内的所有函数的 test
empty test file
生成空 test file, 里面没有 TestFunc
自动补全代码 Ctrl+shfit+enter
- 自动补全右括号
有时候要把莫东西加到括号中,可以先加上左括号,然后对着此行使用,会自动补全右括号并移动到下一行
Before
func main() {
fmt.Println ("Hello World!"
}
After
func main() {
fmt.Println("Hello Wrold!")
}
- 自动补全大括号
有时候大括号多了,会不小心删除右括号,这时候使用会自动生成右括号
Before
func main(){
fmt.Println("hello World!")
After
func main() {
fmt.Println("hello world!")
}
常用 action
- find usage 查找方法被调用的地方