golang中method的传值与传地址

    golang中,struct的method的形式如下:

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

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

    废话少说,代码验证:

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值。

    如果有人感兴趣,我就接着给说道说道。

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

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

再补充两个代码示例:

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)) // 第一个返回值类型
    }
}


 

转载于:https://my.oschina.net/alexstocks/blog/371100

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值