golang中method的传值与传地址

    golang中,struct的method的形式以下:java

    func (r ReceiverType) funcName(parameters) (results)c++

    若是想要修改struct的成员的值,method被定义时候其ReceiverType必须是struct*形式。若是ReceiverType是struct,则没法改变struct成员的值。golang

    废话少说,代码验证:函数

package main

import (
	"fmt"
)

type tag struct {
	value int32
}

func (t tag) Change() {
	t.value = int32(987)
}

// The method set of any other named type T consists of all methods with receiver type T. 
// The method set of the corresponding pointer type *T is the set of all methods with 
// receiver *T or T (that is, it also contains the method set of T).
// 定义receiver的method的时候,通常receiver使用指针形式,由于T也能够调用T*的函数,并可否修改器成员

// 编译器会参考上面的函数隐式的生成下面的函数
// func (t *tag) Change() {
//    t.value = int32(987)
// }

type tag2 struct {
	value int32
}

func (t *tag2) Change() {
	t.value = int32(987)
}

func main() {
	// tag*
	tp := new(tag)
	tp.value = 123
	tp.Change()
	fmt.Println(tp) // &{123}

	// tag
	var tv = *tp
	tv.Change()
	fmt.Println(tv) // {123}

	// tag2
	tv2 := tag2{41}
	tv2.Change()
	fmt.Println(tv2) // {987}

	// tag2*
	var tp2 = &tag2{value: 123}
	tp2.Change()
	fmt.Println(tp2) // &{987}
}

   上面main函数中,第一段代码中对象 tp 的形式为*tag,可是其方法Change没法改变其value值。第二段代码中对象 tv2 的形式为tag2,可是其方法Change却能够改变其value值。this

    若是有人感兴趣,我就接着给说道说道。spa

    golang中的method的第一个参数就是它的Receiver Type,能够是值形式也能够是指针形式,而c++以及其同类语言java等C系语言中method的方法默认是class* this。也就是说,golang中method有传对象值与传对象地址的值两种,而C系语言强制要求传递对象的地址。最终改变对象值与否取决于Receiver Type,而不取决于 object Variable Type。指针

     这么说,就能够理解了吧?Golang中若是函数须要改变对象成员的值,须要Receiver Type为指针形式,若非必要则不要使用指针形式,由于指针形式的对象会被分配在内存堆上,耗费GC资源。code

再补充两个代码示例:对象

example1:内存

/******************************************************
# DESC    :
# AUTHOR  : Alex Stocks
# MOD     : 2016-09-05 07:26
# FILE    : value_ptr_receiver.go
******************************************************/

package main

type tag struct {
}

func (this *tag) String() {
	println("hello")
}

type Tag struct {
}

func (this Tag) String() {
	println("hello")
}

func main() {
	var t tag
	t.String()
	var tt *Tag = &Tag{}
	(*tt).String()
}

example2:

type T struct {
    A int // A is name, int is type, T.A is interface
    B string
}

/*
从test例子能够看出,func (this T) GetTName(str string) string有一个隐式的函数:
func (this *T) GetTName(str string) string
*/
func (this T) GetTName(str string) string {
    this.B = str
    return this.B
}

func (this *T) GetName(str string) string {
    this.B = str
    return this.B
}

func test_field_method() {
    t := T{203, "mh203"}
    // s := reflect.ValueOf(&t).Elem()
    // s := reflect.ValueOf(t)
    s := reflect.Indirect(reflect.ValueOf(t)) // 上面三行等价
    typeOfT := s.Type()

    /*
       0: A int = 203
       1: B string = mh203

    */
    for i := 0; i < s.NumField(); i++ {
        f := s.Field(i)
        fmt.Printf("%d: %s %s = %v\n", i, typeOfT.Field(i).Name, f.Type(), f.Interface())
    }

    /*
       idx: 0
       func(main.T, string) string
       GetTName
       NumIn: 2
       in(0) type: main.T
       in(1) type: string
       NumOut: 1
       out(1) type: string
    */
    for m := 0; m < reflect.TypeOf(t).NumMethod(); m++ {
        fmt.Println("idx:", m)
        method := reflect.TypeOf(t).Method(m)
        fmt.Println(method.Type)                        // func(*main.MyStruct) string
        fmt.Println(method.Name)                        // GetName
        fmt.Println("NumIn:", method.Type.NumIn())      // 参数个数
        fmt.Println("in(0) type:", method.Type.In(0))   // 参数类型
        fmt.Println("in(1) type:", method.Type.In(1))   // 参数类型
        fmt.Println("NumOut:", method.Type.NumOut())    // 返回值个数
        fmt.Println("out(1) type:", method.Type.Out(0)) // 第一个返回值类型
    }

    /*
       idx: 0
       func(*main.T, string) string
       GetName
       NumIn: 2
       in(0) type: *main.T
       in(1) type: string
       NumOut: 1
       out(1) type: string

       idx: 1
       func(*main.T, string) string
       GetTName
       NumIn: 2
       in(0) type: *main.T
       in(1) type: string
       NumOut: 1
       out(1) type: string
    */
    for m := 0; m < reflect.TypeOf(&t).NumMethod(); m++ {
        fmt.Println("idx:", m)
        method := reflect.TypeOf(&t).Method(m)
        fmt.Println(method.Type)                        // func(*main.MyStruct) string
        fmt.Println(method.Name)                        // GetName
        fmt.Println("NumIn:", method.Type.NumIn())      // 参数个数
        fmt.Println("in(0) type:", method.Type.In(0))   // 参数类型
        fmt.Println("in(1) type:", method.Type.In(1))   // 参数类型
        fmt.Println("NumOut:", method.Type.NumOut())    // 返回值个数
        fmt.Println("out(1) type:", method.Type.Out(0)) // 第一个返回值类型
    }
}
相关文章
相关标签/搜索