原則
快捷鍵不能過多
快捷鍵不能過多,一個 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 刪除當前行
插件
- 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 查找方法被調用的地方