请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

有关指针的疑惑

老师您好!有几个有关指针的问题不是很清楚:

我是Java转Go的。

您说到值传递、引用传递这两种,实战时根本不知道到底应该使用值传递,还是引用传递!也就是到底什么场景需要用到指针,什么场景不需要用到指针!

例如这段代码:

package storage

type User struct {
	Name string
	Age int
}

// 获取该用户所属部门
func (u User) GetDepart() string {
	switch {
		case u.Age < 18:
			return "裁缝部"
		case u.Age > 18 && u.Age < 30 :
			return "包装部"
		default:
			return "新人招待部"
	}
}
package main

func main() {
	user := storage.User{
		Name: "张三",
		Age:  24,
	}
	fmt.Println(user.GetDepart())
}
问:

// 上诉代码这个方法 
func (u User) GetDepart() string {
	...
}

// 和这段代码有什么区别?这个地方 *User 到底又做了什么?
func (u *User) GetDepart() string {
	...
}

正在回答 回答被采纳积分+3

2回答

ccmouse 2020-03-18 17:16:36

同学又提到了Java的get/set方法,以及对象创建的问题。

get/set方法是Java推荐的做法,不是说这样“好”,而是整个Java的工具链都基于get/set方法的习惯。

go中我们就没有这样的习惯,而是根据需求来。

如果一个字段又能get又能set,那么就定义成大写的public字段。

如果一个字段是只读的,就定义成小写的private字段,再加一个方法去读它。比如如果Age想只读,就做成User.Age()。

如果所有字段都是只读的,而且这个结构非常小,只是一个自定义的数据结构,比如你这里的这个User类型,可以做成值类型,也就是它里面的方法不使用指针接收者,就像你问题里的代码一样。

如果有些不是纯粹的get/set一个字段,而是相当于java的get/set方法里面还有逻辑。比如你这里的GetDepartment(),我们如果还能set,那么就像Java那样做一对方法。不过不必叫Get/Set,可以是GetDepartment() stirng/Department(string),或者是Department() string/SetDepartment(string)。没有特别的规定。

再说说创建。有两种方法,一个是直接让结构体里有一些public的字段让用户去设置。比如http.Client

https://github.com/golang/go/blob/master/src/net/http/client.go#L58

还有是自己定义一个NewXXX函数,这个名字也没有具体的规定。接收一些参数,来创建我们的对象,比如zap.Logger,它都是private的成员:

https://github.com/uber-go/zap/blob/master/logger.go#L41 

它有多种创建的方法:

zap.New()/zap.NewProduction()/zap.NewDevelopment()/zap.NewExample()等,还可以自己配置:

https://godoc.org/go.uber.org/zap 可以展开下Example (BasicConfiguration)这段。

简单点的话,自己定义NewXXX函数来创建Client的话:

New(param1, param2, param3 string) (*Client, error)

或者参数过多不好看的话:

type Config{

  param1 string

  param2 string

  param3 string

}

New(cfg Config) (*Client, error)

注意这里的NewXXX函数都是普通的函数,不是Client上定义的方法。

1 回复 有任何疑惑可以回复我~
  • hen_nam #1
    好像文档推荐的是 Department() string/SetDepartment(string)
    回复 有任何疑惑可以回复我~ 2022-01-07 15:17:31
ccmouse 2020-03-15 22:29:41

这里我们看不出来,我再加一个方法:

func (u *User) IncreaseAge() {

  u.Age += 1

}

这里就一定要用指针,不使用指针的话,调用user.IncreaseAge()的时候,它其实是拷贝了一个u去调用IncreaseAge(),本身user不会改变。同学可以试一下。

另外,如果我有一个方法是使用指针的,比如这里的IncreaseAge(),那么为了一致性,这个类型所有的方法都推荐使用指针,也就是有IncreaseAge()的话,我们上面的GetDepart也推荐使用指针。

Java所有类里面的方法,其实都相当于go这里的指针类型的方法,Java写不出上述的func (u User) GetDepart() stirng{}这样的方法。

什么时候用指针类型接收者,这里(u User)或者(u *User)叫接收者:

  • 如果要改变结构里的某些字段的值,必须使用指针

  • 如果这个结构字段比较多,空间比较大,推荐使用指针

  • 如果这个结构里的字段值我们不希望改变,比如说坐标,三元组,等等,推荐不使用指针。这种我们也称为“值类型”,在Java中也有这样的提法,Java中我们会做成只有getter没有setter。

  • 最后,如果不确定,也推荐使用指针。所以其实大部分情况下都会使用指针接收者。

0 回复 有任何疑惑可以回复我~
  • 提问者 骑着面包去草原 #1
    这些我似乎明白了一点!
    因为在java中,例如需要对对象进行成员操作,会有Get和Set方法!
    而在GO中,其实就是直接使用指针对对象成员进行直接操作,指针所操作的对象,其实就是它自己本身!是这么理解吗?
    回复 有任何疑惑可以回复我~ 2020-03-16 22:42:08
  • 提问者 骑着面包去草原 #2
    或者说 在使用场景时就必须想好 需要拷贝它还是只改变其值 对吗?
    回复 有任何疑惑可以回复我~ 2020-03-16 22:45:18
  • 提问者 骑着面包去草原 #3
    而且 我一般都习惯按照java的思路走 比如对数据库操作,Create方法 一般这种操作在java中创建成功后会返回一个对象!
    
    而在GO中 需要先定义一个结构体 将结构体地址传给 Create方法 方法只返回一个err!只要这个err不报错 结构体指针对象也会随着改变 这种就叫引用传递
    
    可是按照java思路 我怎么都转不过来!。。。
    回复 有任何疑惑可以回复我~ 2020-03-16 22:49:01
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信