有关指针的疑惑
来源:2-7 指针

骑着面包去草原
2020-03-14
老师您好!有几个有关指针的问题不是很清楚:
我是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 {
...
}
2回答
-
ccmouse
2020-03-18
同学又提到了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上定义的方法。
112022-01-07 -
ccmouse
2020-03-15
这里我们看不出来,我再加一个方法:
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。
最后,如果不确定,也推荐使用指针。所以其实大部分情况下都会使用指针接收者。
032020-03-16
相似问题