[golang] インターフェースが確定でヒープに割り当てられるというルールはない

# 目的
インターフェースが確定でヒープに割り当てられるというルールは特にないということを理解する。
下記の記事で、インターフェースは確定でヒープに配置されるという旨の記述があったので検証してみた。かなり古い記事なので、昔の golang はそういう仕様だったということかもしれない。

https://najeira.blogspot.com/2013/10/go.html

# 環境
```
$ go version
go version go1.23.2 linux/amd64
```

# 検証
`./main.go:16:18: &Duck{} does not escape` より、インターフェースはスタックに配置されていることがわかる。
つまり、検証対象の記事の主張は、現在のバージョンでは間違っているということである。


```
package main

import "fmt"

type Sounder interface {
	Sound()
}

type Duck struct{}

func (d *Duck) Sound() {
	fmt.Println("quack")
}

func main() {
	var d Sounder = &Duck{}
	d.Sound()
}

```
```
package main

import "testing"

func Benchmark(b *testing.B) {
	for i := 0; i < b.N; i++ {
		main()
	}
}

```
```
$ go build -gcflags "-m=2" .
# gopractice
./main.go:11:6: can inline (*Duck).Sound with cost 78 as: method(*Duck) func() { fmt.Println(... argument...) }
./main.go:15:6: can inline main with cost 67 as: func() { d := &Duck{}; d.Sound() }
./main.go:12:13: inlining call to fmt.Println
./main.go:17:9: devirtualizing d.Sound to *Duck
./main.go:17:9: inlining call to (*Duck).Sound
./main.go:17:9: inlining call to fmt.Println
./main.go:12:14: "quack" escapes to heap:
./main.go:12:14:   flow: {storage for ... argument} = &{storage for "quack"}:
./main.go:12:14:     from "quack" (spill) at ./main.go:12:14
./main.go:12:14:     from ... argument (slice-literal-element) at ./main.go:12:13
./main.go:12:14:   flow: fmt.a = &{storage for ... argument}:
./main.go:12:14:     from ... argument (spill) at ./main.go:12:13
./main.go:12:14:     from fmt.a := ... argument (assign-pair) at ./main.go:12:13
./main.go:12:14:   flow: {heap} = *fmt.a:
./main.go:12:14:     from fmt.Fprintln(os.Stdout, fmt.a...) (call parameter) at ./main.go:12:13
./main.go:11:7: d does not escape
./main.go:12:13: ... argument does not escape
./main.go:12:14: "quack" escapes to heap
./main.go:17:9: "quack" escapes to heap:
./main.go:17:9:   flow: {storage for ... argument} = &{storage for "quack"}:
./main.go:17:9:     from "quack" (spill) at ./main.go:17:9
./main.go:17:9:     from ... argument (slice-literal-element) at ./main.go:17:9
./main.go:17:9:   flow: fmt.a = &{storage for ... argument}:
./main.go:17:9:     from ... argument (spill) at ./main.go:17:9
./main.go:17:9:     from fmt.a := ... argument (assign-pair) at ./main.go:17:9
./main.go:17:9:   flow: {heap} = *fmt.a:
./main.go:17:9:     from fmt.Fprintln(os.Stdout, fmt.a...) (call parameter) at ./main.go:17:9
./main.go:16:18: &Duck{} does not escape
./main.go:17:9: ... argument does not escape
./main.go:17:9: "quack" escapes to heap
<autogenerated>:1: parameter ~p0 leaks to {heap} with derefs=0:
<autogenerated>:1:   flow: {heap} = ~p0:
<autogenerated>:1:     from ~p0.Sound() (call parameter) at <autogenerated>:1
```
```
$ go test -bench=. -benchmem
...
quack
...
  320628              6311 ns/op               0 B/op          0 allocs/op
PASS
ok      gopractice      2.073s
```
```
$ go build -o main_binary main.go
$ objdump -d main_binary > objdump.txt
000000000048f140 <main.main>:
  48f140:	49 3b 66 10          	cmp    0x10(%r14),%rsp
  48f144:	76 47                	jbe    48f18d <main.main+0x4d>
  48f146:	55                   	push   %rbp
  48f147:	48 89 e5             	mov    %rsp,%rbp
  48f14a:	48 83 ec 38          	sub    $0x38,%rsp
  48f14e:	90                   	nop
  48f14f:	48 8d 15 aa 95 00 00 	lea    0x95aa(%rip),%rdx        # 498700 <type:*+0x8700>
  48f156:	48 89 54 24 28       	mov    %rdx,0x28(%rsp)
  48f15b:	48 8d 15 b6 4f 04 00 	lea    0x44fb6(%rip),%rdx        # 4d4118 <runtime.buildVersion.str+0x10>
  48f162:	48 89 54 24 30       	mov    %rdx,0x30(%rsp)
  48f167:	48 8b 1d fa 32 0c 00 	mov    0xc32fa(%rip),%rbx        # 552468 <os.Stdout>
  48f16e:	48 8d 05 e3 54 04 00 	lea    0x454e3(%rip),%rax        # 4d4658 <go:itab.*os.File,io.Writer>
  48f175:	48 8d 4c 24 28       	lea    0x28(%rsp),%rcx
  48f17a:	bf 01 00 00 00       	mov    $0x1,%edi
  48f17f:	48 89 fe             	mov    %rdi,%rsi
  48f182:	e8 b9 af ff ff       	call   48a140 <fmt.Fprintln>
  48f187:	48 83 c4 38          	add    $0x38,%rsp
  48f18b:	5d                   	pop    %rbp
  48f18c:	c3                   	ret
  48f18d:	e8 4e aa fd ff       	call   469be0 <runtime.morestack_noctxt.abi0>
  48f192:	eb ac                	jmp    48f140 <main.main>
```
```
$ go run main.go
quack
```

# おまけ
`./main.go:17:9: "quack" escapes to heap` は、`fmt` パッケージの`Println` 関数に文字列を渡すと、文字列がヒープにエスケープされることを示している。

https://pkg.go.dev/fmt#Println

```
func Println(a ...any) (n int, err error)
```


https://www.amazon.co.jp/Go%E8%A8%80%E8%AA%9E-100Tips-%E3%81%82%E3%82%8A%E3%81%8C%E3%81%A1%E3%81%AA%E3%83%9F%E3%82%B9%E3%82%92%E6%8A%8A%E6%8F%A1%E3%81%97%E3%80%81%E5%AE%9F%E8%A3%85%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%99%E3%82%8B-impress-gear/dp/4295017531

> 文字列はほとんどがポインタなので、文字列を渡すために関数を呼び出しても、バイトの深いコピーは行われません。浅くコピーされた文字列は、依然として同じ基底配列を参照しています。

# 参考

https://najeira.blogspot.com/2013/10/go.html

https://pkg.go.dev/fmt#Println

https://www.amazon.co.jp/Go%E8%A8%80%E8%AA%9E-100Tips-%E3%81%82%E3%82%8A%E3%81%8C%E3%81%A1%E3%81%AA%E3%83%9F%E3%82%B9%E3%82%92%E6%8A%8A%E6%8F%A1%E3%81%97%E3%80%81%E5%AE%9F%E8%A3%85%E3%82%92%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%99%E3%82%8B-impress-gear/dp/4295017531