// Sample program to show the basic concept of pass by value.
package main
func main() {
// Declare variable of type int with a value of 10.
count := 10
// Display the "value of" and "address of" count.
println("count:\tValue Of[", count, "]\tAddr Of[", &count, "]")
// Pass the "value of" the count.
increment(count)
println("count:\tValue Of[", count, "]\tAddr Of[", &count, "]")
}
// increment declares count as a pointer variable whose value is
// always an address and points to values of type int.
//增量声明count作为一个指针变量,其值为。
//始终是一个地址,并指向int类型的值。
//go:noinline
func increment(inc int) {
// Increment the "value of" inc.
inc++
println("inc:\tValue Of[", inc, "]\tAddr Of[", &inc, "]")
}
/*
count: Value Of[ 10 ] Addr Of[ 0xc420045f68 ]
inc: Value Of[ 11 ] Addr Of[ 0xc420045f58 ]
count: Value Of[ 10 ] Addr Of[ 0xc420045f68 ]
*/
Sharing data I
// Sample program to show the basic concept of using a pointer
// to share data.
package main
func main() {
// Declare variable of type int with a value of 10.
count := 10
// Display the "value of" and "address of" count.
println("1.count:\tValue Of[", count, "]\t\tAddr Of[", &count, "]")
// Pass the "address of" count.
increment(&count)
println("3.count:\tValue Of[", count, "]\t\tAddr Of[", &count, "]")
}
// increment declares count as a pointer variable whose value is
// always an address and points to values of type int.
//go:noinline
func increment(inc *int) {
// Increment the "value of" count that the "pointer points to".
*inc++
println("2.inc:\tValue Of[", inc, "]\tAddr Of[", &inc, "]\tValue Points To[", *inc, "]")
}
/*
1.count: Value Of[ 10 ] Addr Of[ 0xc420045f68 ]
2.inc: Value Of[ 0xc420045f68 ] Addr Of[ 0xc420045f58 ] Value Points To[ 11 ]
3.count: Value Of[ 11 ] Addr Of[ 0xc420045f68 ]
*/
Sharing data II
// Sample program to show the basic concept of using a pointer
// to share data.
//示例程序演示使用指针的基本概念。
//分享数据。
package main
import "fmt"
// user represents a user in the system.//用户代表系统中的用户。
type user struct {
name string
email string
logins int
}
func main() {
// Declare and initialize a variable named bill of type user.
bill := user{
name: "Bill",
email: "bill@ardanlabs.com",
}
//** We don‘t need to include all the fields when specifying field
// names with a struct literal.
// Pass the "address of" the bill value. 通过“地址”的票据价值。
display(&bill)
// Pass the "address of" the logins field from within the bill value.
increment(&bill.logins)
// Pass the "address of" the bill value.
display(&bill)
}
// increment declares logins as a pointer variable whose value is
// always an address and points to values of type int.
func increment(logins *int) {
*logins++
fmt.Printf("&logins[%p] logins[%p] *logins[%d]\n", &logins, logins, *logins)
}
// display declares u as user pointer variable whose value is always an address
// and points to values of type user.
func display(u *user) {
fmt.Printf("%p\t%+v\n", u, *u)
}
/*
0xc42007a180 {name:Bill email:bill@ardanlabs.com logins:0}
&logins[0xc42000c030] logins[0xc42007a1a0] *logins[1]
0xc42007a180 {name:Bill email:bill@ardanlabs.com logins:1}
*/
Escape Analysis 溢出分析
//逸出分析
// Escape Analysis
// Escape Analysis Flaws:
// https://docs.google.com/document/d/1CxgUBPlx9iJzkz9JWkb6tIpTe5q32QDmz8l0BouG0Cw/view
// Sample program to teach the mechanics of escape analysis.
package main
// user represents a user in the system.
type user struct {
name string
email string
}
// main is the entry point for the application.
func main() {
u1 := createUserV1()
u2 := createUserV2()
println("u1", &u1, "u2", &u2)
/*
V1 0xc420045ef8
V2 0xc42000a040
u1 0xc420045f50 u2 0xc420045f48
*/
}
// createUserV1 creates a user value and passed
// a copy back to the caller.
//go:noinline
func createUserV1() user {
u := user{
name: "Bill",
email: "bill@ardanlabs.com",
}
println("V1", &u)
return u
}
// createUserV2 creates a user value and shares
// the value with the caller.
//go:noinline
func createUserV2() *user {
u := user{
name: "Bill",
email: "bill@ardanlabs.com",
}
println("V2", &u)
return &u
}
/*
// See escape analysis and inling decisions.
$ go build -gcflags "-m -m"
# github.com/ardanlabs/gotraining/topics/go/language/pointers/example4
./example4.go:27: cannot inline createUserV1: marked go:noinline
./example4.go:41: cannot inline createUserV2: marked go:noinline
./example4.go:17: cannot inline main: non-leaf function
./example4.go:33: createUserV1 &u does not escape
./example4.go:49: &u escapes to heap
./example4.go:49: from ~r0 (return) at ./example4.go:49
./example4.go:45: moved to heap: u
./example4.go:47: createUserV2 &u does not escape
./example4.go:21: main &u1 does not escape
./example4.go:21: main &u2 does not escape
// See the intermediate assembly phase before
// generating the actual arch-specific assembly.
$ go build -gcflags -S
"".createUserV1 t=1 size=221 args=0x20 locals=0x38
0x0000 00000 (github.com/ardanlabs/gotraining/.../example4.go:27) TEXT "".createUserV1(SB), $56-32
0x0000 00000 (github.com/ardanlabs/gotraining/.../example4.go:27) MOVQ (TLS), CX
0x0009 00009 (github.com/ardanlabs/gotraining/.../example4.go:27) CMPQ SP, 16(CX)
0x000d 00013 (github.com/ardanlabs/gotraining/.../example4.go:27) JLS 211
0x0013 00019 (github.com/ardanlabs/gotraining/.../example4.go:27) SUBQ $56, SP
0x0017 00023 (github.com/ardanlabs/gotraining/.../example4.go:27) MOVQ BP, 48(SP)
0x001c 00028 (github.com/ardanlabs/gotraining/.../example4.go:27) LEAQ 48(SP), BP
// See the actual machine representation by using
// the disasembler.
$ go tool objdump -s main.main example4
TEXT main.main(SB) github.com/ardanlabs/gotraining/topics/go/language/pointers/example4/example4.go
example4.go:18 0x104bf31 e8ba000000 CALL main.createUserV1(SB)
example4.go:18 0x104bf36 488b0424 MOVQ 0(SP), AX
example4.go:18 0x104bf3a 488b4c2408 MOVQ 0x8(SP), CX
example4.go:18 0x104bf3f 488b542410 MOVQ 0x10(SP), DX
example4.go:18 0x104bf44 488b5c2418 MOVQ 0x18(SP), BX
example4.go:18 0x104bf49 4889442428 MOVQ AX, 0x28(SP)
example4.go:18 0x104bf4e 48894c2430 MOVQ CX, 0x30(SP)
example4.go:18 0x104bf53 4889542438 MOVQ DX, 0x38(SP)
example4.go:18 0x104bf58 48895c2440 MOVQ BX, 0x40(SP)
// See a list of the symbols in an artifact with
// annotations and size.
$ go tool nm example4
104bff0 T main.createUserV1
104c0d0 T main.createUserV2
104c1e0 T main.init
10b2940 B main.initdone.
104bf10 T main.main
106cf80 R main.statictmp_4
*/
// Sample program to show how stacks grow/change.
package main
// Number of elements to grow each stack frame.
// Run with 10 and then with 1024
const size = 1024
// main is the entry point for the application.
func main() {
s := "HELLO"
stackCopy(&s, 0, [size]int{})
}
// stackCopy recursively runs increasing the size
// of the stack.
func stackCopy(s *string, c int, a [size]int) {
println(c, s, *s)
c++
if c == 10 {
return
}
stackCopy(s, c, a)
}
/*
0 0xc420089f60 HELLO
1 0xc420089f60 HELLO
2 0xc420099f60 HELLO
3 0xc420099f60 HELLO
4 0xc420099f60 HELLO
5 0xc420099f60 HELLO
6 0xc4200b9f60 HELLO
7 0xc4200b9f60 HELLO
8 0xc4200b9f60 HELLO
9 0xc4200b9f60 HELLO
*/
练习
package main
import "fmt"
func main() {
// Declare an integer variable with the value of 20.
value := 20
// Display the address of and value of the variable.
fmt.Println("Address Of:", &value, "Value Of:", value)
// Declare a pointer variable of type int. Assign the
// address of the integer variable above.
p := &value
// Display the address of, value of and the value the pointer
// points to.
fmt.Println("Address Of:", &p, "Value Of:", p, "Points To:", *p)
}
/*
Address Of: 0xc4200140a0 Value Of: 20
Address Of: 0xc42000c030 Value Of: 0xc4200140a0 Points To: 20
*/
// Declare a struct type and create a value of this type. Declare a function
// that can change the value of some field in this struct type. Display the
// value before and after the call to your function.
package main
import "fmt"
// user represents a user in the system.
type user struct {
name string
email string
accessLevel int
}
func main() {
// Create a variable of type user and initialize each field.
bill := user{
name: "Bill",
email: "bill@ardanlabs.com",
accessLevel: 1,
}
// Display the value of the accessLevel field.
fmt.Println("access:", bill.accessLevel)
// Share the bill variable with the accessLevel function
// along with a value to update the accessLevel field with.
accessLevel(&bill, 10)
// Display the value of the accessLevel field again.
fmt.Println("access:", bill.accessLevel)
}
// accessLevel changes the value of the users access level.
func accessLevel(u *user, accessLevel int) {
// Set of value of the accessLevel field to the value
// that is passed in.
u.accessLevel = accessLevel
}
/*
access: 1
access: 10
*/