Smart clean code
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseList(head *ListNode) *ListNode {
var p *ListNode
for head != nil {
head.Next, head, p = p, head.Next, head // ??? 某些人可能困惑在这里
}
return p
}
尼古拉斯·永强
leave a comment :
I learn it from google that the assignment is from the left to the right. So the point I do not get is that when head.Next=prev
at the initial time, it equals to nil
, and then why using head=head.Next
could make it works? For me, I think head.Next
equals nil
at that moment. Correct me if I was wrong.
我们使用 dlv,go的一个 debug
命令行工具来观看下
# logan at macmadeMacBook-Pro.local in ~/go/src/leetcode/tmp
→ dlv debug main.go master ✖︎ [9:44:25]
Type 'help' for list of commands.
(dlv) b main.main
Breakpoint 1 set at 0x10c2398 for main.main() ./main.go:5
(dlv) c
> main.main() ./main.go:5 (hits goroutine(1):1 total:1) (PC: 0x10c2398)
1: package main
2:
3: import "fmt"
4:
=> 5: func main() {
6: a, b, c, d := 1, 2, 3, 4
7: b, c, d, a = a, b, c, d
8: fmt.Println(a, b, c, d)
9: }
(dlv) disassemble
TEXT main.main(SB) /Users/logan/go/src/leetcode/tmp/main.go
main.go:5 0x10c2380 65488b0c2530000000 mov rcx, qword ptr gs:[0x30]
main.go:5 0x10c2389 488d442490 lea rax, ptr [rsp-0x70]
main.go:5 0x10c238e 483b4110 cmp rax, qword ptr [rcx+0x10]
main.go:5 0x10c2392 0f8620020000 jbe 0x10c25b8
=> main.go:5 0x10c2398* 4881ecf0000000 sub rsp, 0xf0
main.go:5 0x10c239f 4889ac24e8000000 mov qword ptr [rsp+0xe8], rbp
main.go:5 0x10c23a7 488dac24e8000000 lea rbp, ptr [rsp+0xe8]
main.go:6 0x10c23af 48c744244801000000 mov qword ptr [rsp+0x48], 0x1 // a := 1
main.go:6 0x10c23b8 48c744244002000000 mov qword ptr [rsp+0x40], 0x2 // b := 2
main.go:6 0x10c23c1 48c744243803000000 mov qword ptr [rsp+0x38], 0x3 // c := 3
main.go:6 0x10c23ca 48c744243004000000 mov qword ptr [rsp+0x30], 0x4 // d := 4
main.go:7 0x10c23d3 488b442440 mov rax, qword ptr [rsp+0x40]
main.go:7 0x10c23d8 4889442460 mov qword ptr [rsp+0x60], rax // 0x60 := b 相当于临时变量
main.go:7 0x10c23dd 488b442438 mov rax, qword ptr [rsp+0x38]
main.go:7 0x10c23e2 4889442458 mov qword ptr [rsp+0x58], rax // 0x58 := c 相当于临时变量
main.go:7 0x10c23e7 488b442430 mov rax, qword ptr [rsp+0x30]
main.go:7 0x10c23ec 4889442450 mov qword ptr [rsp+0x50], rax // 0x50 := d 相当于临时变量
main.go:7 0x10c23f1 488b442448 mov rax, qword ptr [rsp+0x48]
main.go:7 0x10c23f6 4889442440 mov qword ptr [rsp+0x40], rax // 0x40 := a -> b = a
main.go:7 0x10c23fb 488b442460 mov rax, qword ptr [rsp+0x60]
main.go:7 0x10c2400 4889442438 mov qword ptr [rsp+0x38], rax // 0x38 = 0x60 -> c = b
main.go:7 0x10c2405 488b442458 mov rax, qword ptr [rsp+0x58]
main.go:7 0x10c240a 4889442430 mov qword ptr [rsp+0x30], rax // 0x30 = 0x58 -> d = c
main.go:7 0x10c240f 488b442450 mov rax, qword ptr [rsp+0x50]
main.go:7 0x10c2414 4889442448 mov qword ptr [rsp+0x48], rax // 0x48 = 0x50 -> a = d
main.go:8 0x10c2419 48890424 mov qword ptr [rsp], rax
main.go:8 0x10c241d e87e78f4ff call $runtime.convT64
main.go:8 0x10c2422 488b442408 mov rax, qword ptr [rsp+0x8]
main.go:8 0x10c2427 4889442470 mov qword ptr [rsp+0x70], rax //
main.go:8 0x10c242c 488b442440 mov rax, qword ptr [rsp+0x40]
main.go:8 0x10c2431 48890424 mov qword ptr [rsp], rax
main.go:8 0x10c2435 e86678f4ff call $runtime.convT64
main.go:8 0x10c243a 488b442408 mov rax, qword ptr [rsp+0x8]
main.go:8 0x10c243f 4889442468 mov qword ptr [rsp+0x68], rax
main.go:8 0x10c2444 488b442438 mov rax, qword ptr [rsp+0x38]
main.go:8 0x10c2449 48890424 mov qword ptr [rsp], rax
main.go:8 0x10c244d e84e78f4ff call $runtime.convT64
main.go:8 0x10c2452 488b442408 mov rax, qword ptr [rsp+0x8]
main.go:8 0x10c2457 4889842488000000 mov qword ptr [rsp+0x88], rax
main.go:8 0x10c245f 488b442430 mov rax, qword ptr [rsp+0x30]
main.go:8 0x10c2464 48890424 mov qword ptr [rsp], rax
main.go:8 0x10c2468 e83378f4ff call $runtime.convT64
main.go:8 0x10c246d 488b442408 mov rax, qword ptr [rsp+0x8]
main.go:8 0x10c2472 4889842480000000 mov qword ptr [rsp+0x80], rax
main.go:8 0x10c247a 0f57c0 xorps xmm0, xmm0
main.go:8 0x10c247d 0f118424a8000000 movups xmmword ptr [rsp+0xa8], xmm0
main.go:8 0x10c2485 0f57c0 xorps xmm0, xmm0
main.go:8 0x10c2488 0f118424b8000000 movups xmmword ptr [rsp+0xb8], xmm0
main.go:8 0x10c2490 0f57c0 xorps xmm0, xmm0
main.go:8 0x10c2493 0f118424c8000000 movups xmmword ptr [rsp+0xc8], xmm0
main.go:8 0x10c249b 0f57c0 xorps xmm0, xmm0
main.go:8 0x10c249e 0f118424d8000000 movups xmmword ptr [rsp+0xd8], xmm0
main.go:8 0x10c24a6 488d8424a8000000 lea rax, ptr [rsp+0xa8]
main.go:8 0x10c24ae 4889442478 mov qword ptr [rsp+0x78], rax
main.go:8 0x10c24b3 8400 test byte ptr [rax], al
main.go:8 0x10c24b5 488b4c2470 mov rcx, qword ptr [rsp+0x70]
main.go:8 0x10c24ba 488d15dfdd0000 lea rdx, ptr [rip+0xdddf]
main.go:8 0x10c24c1 48899424a8000000 mov qword ptr [rsp+0xa8], rdx
main.go:8 0x10c24c9 48898c24b0000000 mov qword ptr [rsp+0xb0], rcx
main.go:8 0x10c24d1 8400 test byte ptr [rax], al
main.go:8 0x10c24d3 488b442468 mov rax, qword ptr [rsp+0x68]
main.go:8 0x10c24d8 488d0dc1dd0000 lea rcx, ptr [rip+0xddc1]
main.go:8 0x10c24df 48898c24b8000000 mov qword ptr [rsp+0xb8], rcx
main.go:8 0x10c24e7 48898424c0000000 mov qword ptr [rsp+0xc0], rax
main.go:8 0x10c24ef 488b442478 mov rax, qword ptr [rsp+0x78]
main.go:8 0x10c24f4 8400 test byte ptr [rax], al
main.go:8 0x10c24f6 488b8c2488000000 mov rcx, qword ptr [rsp+0x88]
main.go:8 0x10c24fe 488d159bdd0000 lea rdx, ptr [rip+0xdd9b]
main.go:8 0x10c2505 48895020 mov qword ptr [rax+0x20], rdx
main.go:8 0x10c2509 488d7828 lea rdi, ptr [rax+0x28]
main.go:8 0x10c250d 833d6c37100000 cmp dword ptr [runtime.writeBarrier], 0x0
main.go:8 0x10c2514 7405 jz 0x10c251b
main.go:8 0x10c2516 e990000000 jmp 0x10c25ab
main.go:8 0x10c251b 48894828 mov qword ptr [rax+0x28], rcx
main.go:8 0x10c251f eb00 jmp 0x10c2521
main.go:8 0x10c2521 488b4c2478 mov rcx, qword ptr [rsp+0x78]
main.go:8 0x10c2526 8401 test byte ptr [rcx], al
main.go:8 0x10c2528 488b842480000000 mov rax, qword ptr [rsp+0x80]
main.go:8 0x10c2530 488d1569dd0000 lea rdx, ptr [rip+0xdd69]
main.go:8 0x10c2537 48895130 mov qword ptr [rcx+0x30], rdx
main.go:8 0x10c253b 488d7938 lea rdi, ptr [rcx+0x38]
main.go:8 0x10c253f 833d3a37100000 cmp dword ptr [runtime.writeBarrier], 0x0
main.go:8 0x10c2546 7402 jz 0x10c254a
main.go:8 0x10c2548 eb5a jmp 0x10c25a4
main.go:8 0x10c254a 48894138 mov qword ptr [rcx+0x38], rax
main.go:8 0x10c254e eb00 jmp 0x10c2550
main.go:8 0x10c2550 488b442478 mov rax, qword ptr [rsp+0x78]
main.go:8 0x10c2555 8400 test byte ptr [rax], al
main.go:8 0x10c2557 eb00 jmp 0x10c2559
main.go:8 0x10c2559 4889842490000000 mov qword ptr [rsp+0x90], rax
main.go:8 0x10c2561 48c784249800000004000000 mov qword ptr [rsp+0x98], 0x4
main.go:8 0x10c256d 48c78424a000000004000000 mov qword ptr [rsp+0xa0], 0x4
main.go:8 0x10c2579 48890424 mov qword ptr [rsp], rax
main.go:8 0x10c257d 48c744240804000000 mov qword ptr [rsp+0x8], 0x4
main.go:8 0x10c2586 48c744241004000000 mov qword ptr [rsp+0x10], 0x4
main.go:8 0x10c258f e87c9fffff call $fmt.Println
main.go:9 0x10c2594 488bac24e8000000 mov rbp, qword ptr [rsp+0xe8]
main.go:9 0x10c259c 4881c4f0000000 add rsp, 0xf0
main.go:9 0x10c25a3 c3 ret
main.go:8 0x10c25a4 e89714faff call $runtime.gcWriteBarrier
main.go:8 0x10c25a9 eba5 jmp 0x10c2550
main.go:8 0x10c25ab 4889c8 mov rax, rcx
main.go:8 0x10c25ae e88d14faff call $runtime.gcWriteBarrier
main.go:8 0x10c25b3 e969ffffff jmp 0x10c2521
main.go:5 0x10c25b8 e863f6f9ff call $runtime.morestack_noctxt
<autogenerated>:1 0x10c25bd e9befdffff jmp $main.main
上述过程中:main.go:7
行显示,b c d tmps 三个变量创建了三个临时变量,之后,把a赋值给b,b tmp 赋值给c , c tmp 赋值给 d, d tmp 赋值给 a。给我个人理解来说,在java中,变量交换使用了临时变量。只不过是显示处理(由程序员处理),而go中的变量交换。只不过是编译器给我们做了相关的处理。go语言本身就是以简单为目标。编译器能做的事,就做了。程序员就不用考虑创建临时变量来处理交换变量的值的问题了。
所以LeetCode的206题,上面的写法也相当于。LeetCode内存占用一致。
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseList(head *ListNode) *ListNode {
var p *ListNode
for head != nil {
t := head.Next
head.Next = p
p = head
head = t
}
return p
}
mov rax, qword ptr [rsp+0x40]
mov : This is the opcode part of the instruction. It describes the base operation the CPU is required to perform. mov
is an opcode instructing a CPU to copy data from the second operand to the first operand. The first operand on the mov
instruction is a target operand, and the second is the source.
也就是说mov是个cpu指令,让第二个参数src,拷贝到第一个参数dst上。
base : https://reverseengineering.stackexchange.com/questions/10746/what-does-mov-qword-ptr-dsrax18-r8-mean