// 演示 go编译器内部真实处理的三种方式
//
//
//总结一下 go的method ，不管是定义在指针上或者是值上的方法，用值和指针都可以取到，
//第二：定义在指针上的方法，你根本不用取* 值就可以获取到结果，因为编译器帮你做了，
//这个仅仅是在对象取值这一步仅此而已。如果你的value是指针类型，然后你还是想对它进行处理的时候你需要取值才能操作，
//因为一个指针 一个钥匙啥的完全没办法操作值，所以go的编译器经常帮你做了很多事情，第一个说明里 & *的智能添加，
//第二个说名中 对指针对象自动取值的添加。这是两部分，
package main

import "fmt"

func main() {
	// 第一种帮你自动取&
	ts := a{
		"12",
	}
	ts.tt()

	//内部是：
	ts = a{
		"12",
	}
	(&ts).tt()

	// 第二种帮你自动取*
	tss := new(a)
	tss.ttpl()

	//内部是：
	tss = new(a)
	(*tss).ttpl()

	// 上面是第一种情况的说明，

	//第二种情况

	tsss := new(a)
	tsss.tt()
	// 看内部说明

	//func (a1 *a) tt() {
	//	a1.value += "1"
	//	fmt.Println(a1.value)
	//}

	//这里面 a1 是 a的指针类型，然后输入的也是指针，这个没的说，但是能取到value值，就不能了，原因是编译器做了：
	//(*a1).value

	//ps:下面说明一种情况 上面的第一种情况下，系统帮你自动取了& 是因为要满足"定义在指针上的方法" 这个要求，然后内部就又
	// 取了* 获取了值才能获取对象。这是编译器的内部过程。

}

type a struct {
	value string
}

func (a1 *a) tt() { //常用模式
	a1.value += "1"
	fmt.Println(a1.value)
}

//func (a1 *a) tt() { //这个才是内部实现的真实面貌。
//	(*a1).value += "1"
//	fmt.Println((*a1).value)
//	fmt.Println("这才是真实的面貌")
//}

func (a2 a) ttpl() {
	a2.value += "1"
	fmt.Println(a2.value)
}

// ps: 如果是在接口中，这个规则就改了，谁实现的方法谁才能实现这个接口(这里面的谁谁 说的是 指针类型和 值类型)
// 说到go的编译器，其实 例如闭包 循环体中的变量，都是用的引用类型，在用的时候go编译器直接给你自动取* 了。这就是编译器的小技巧了。


// ## 输出结果：
//证明了理论。以后定将剖析 go的源代码来看看编译器这个小家伙到底是怎么做到的。
// 121
// 121
// 1
// 1
// 1

