Go 中为啥喜欢这样创建变量

2020-08-03 11:52:18 +08:00
 Ansen

经常能看到类似 newRouter 这样的代码

type router struct {
	roots    map[string]*node
	handlers map[string]HandleFunc
}

func newRouter() *router {
	return &router{
		roots:    make(map[string]*node),
		handlers: make(map[string]HandlerFunc),
	}
}

func (r *router) AddRoute(method string, pattern string, handler HandleFunc) 
func (r *router) getRoute(method string, path string) (*node, map[string]string)

然后在其它地方这样调用

r := newRouter()
r.AddRoute()

为啥不直接这样呢?

var r router

代码都能看懂,但是不知道为啥喜欢这样用,或者这样用的好处是啥?

我能想到的是:

  1. 通过指针来保证代码块中访问的一致性
  2. 避免参数复制产生的内存消耗

还有其它的好处吗?

在其它项目中还会看到这样的代码

package gulu
 // ..........

// Result represents a common-used result struct.
type Result struct {
	Code int         `json:"code"` // return code
	Msg  string      `json:"msg"`  // message
	Data interface{} `json:"data"` // data object
}

// NewResult creates a result with Code=0, Msg="", Data=nil.
func (*GuluRet) NewResult() *Result {
	return &Result{
		Code: 0,
		Msg:  "",
		Data: nil,
	}
}
package controller
// .... 
func addSymArticleAction(c *gin.Context) {
	result := gulu.Ret.NewResult()
	defer c.JSON( http.StatusOK, result)

	arg := map[string]interface{}{}
	if err := c.BindJSON(&arg); nil != err {
		result.Code = util.CodeErr
		result.Msg = "parses add article request failed"

		return
	}
    // ....
}
6972 次点击
所在节点    Go 编程语言
43 条回复
NCZkevin
2020-08-03 15:30:59 +08:00
go 开发团队喜欢简洁,导致 go 有很多特有的写法,适应了很久才习惯
CNife
2020-08-03 15:31:33 +08:00
@vvmint233 var name Type 不能叫声明,应该叫零值初始化,确实分配了内存也赋予了零值。
neoblackcap
2020-08-03 15:37:58 +08:00
默认的构造函数没有什么用,C++里面要删除各种默认的构造函数的情况还少么?这个真的不是什么黑点,构造函数本质上跟现在这样的静态函数没有什么区别。
KickAssTonight
2020-08-03 15:38:56 +08:00
主要是因为没有构造方法吧
Jirajine
2020-08-03 15:47:03 +08:00
@szzhiyang 楼里都在说 constructor 的问题,这个不是 constructor 的问题,而是 go 自作聪明搞得所有变量都默认初始化。
正确的做法是编译器静态检查访问所有对未初始化变量的访问并在编译时报错,而不是给个不正确的初始值然后运行时爆炸。
这种默认初始化值还有一些其他问题,比如 int 传个 0 进来你不知道它是 uninitialized 还是就是 0 。
icexin
2020-08-03 16:03:44 +08:00
go 的变量初始化就是申请内存,然后 memset 为 0 。如果需要额外的初始化就用一个函数来进行初始化工作,思路很清晰。这一块倒是贯彻了 python 里面的 Explicit is better than implicit 。隐式的构造函数看着很方便,但有时候反而带来了无谓的开销。
vvmint233
2020-08-03 16:35:38 +08:00
@CNife 是我不严谨了, 因为 nil 我更习惯叫声明
szzhiyang
2020-08-03 16:42:25 +08:00
@Jirajine 也许是因为检查各个变量是否被初始化会让编译期检查变得复杂且缓慢吧,Go 有不少设计就是为了确保编译流程简单且迅速。
dog82
2020-08-03 16:42:44 +08:00
我写了 2 年多 Go 了,还是对某些语法很排斥。
特别是类型转换,有时会被气爆炸!
uint32 不能隐式转成 uint64
MiskoLee
2020-08-03 16:44:17 +08:00
不知道 LS 一段人在说什么。。。。。。。

这个东西叫做 类型断言。。。。。。,很多现代静态语言都有这个功能,比如 Rust 。
tairan2006
2020-08-03 17:19:50 +08:00
就是初始化的问题,go 没构造函数其实影响不大
janxin
2020-08-03 18:02:47 +08:00
@Jirajine 这只是一个 null safety 问题,至于需要确认是否初始化有其他方式可以确定。

在其他语言里也不是什么很特殊的东西。

https://kotlinlang.org/docs/reference/null-safety.html
https://dart.dev/null-safety/understanding-null-safety
keepeye
2020-08-03 18:08:25 +08:00
默认值呗
janxin
2020-08-03 18:10:10 +08:00
关于 null safety,谷歌开发者有一篇文章关于这个问题( Dart ):

https://mp.weixin.qq.com/s/rgVJn928fyGunNO5kDKnSA

但是如果允许 nil 这个特殊类型之后,如果库出现了问题,在没有异常处理的 Go 语言里没处理好可能程序动不动就崩了...
nuk
2020-08-03 18:18:53 +08:00
你这里 struct 的 field 都导出了,要是有没导出的咋办?
这个用法基本上和 typedef 一个未声明结构的指针差不多
只能从函数返回,实际上无法实例化
zxlzy
2020-08-03 19:17:19 +08:00
这不就是构造函数吗
reus
2020-08-03 20:33:17 +08:00
@Jirajine 连零值的概念都不懂,就别满嘴糟粕糟粕了。map 的零值就是 nil,为啥?如果我只是想声明一个 map 变量,在用现有的 map 赋值,那声明的时候就初始化一个空的干嘛?多余!
petelin
2020-08-03 20:45:01 +08:00
@Jirajine 这就是构造函数啊,难道你们构造东西的时候不写点逻辑进去?

还有,把创建的地方收在一起后期改造也好改啊, 要不然自己去初始化,项目里边 100 多个地方都 create,你想改个默认值都不能改。

唉。。。
petelin
2020-08-03 20:46:15 +08:00
真的忍不住吐槽, 没有基本代码素养的人太多了。。。一个现代的语言动不动被吐槽糟粕。 真正的糟粕是 js 这种历史包袱一大堆的垃圾好吗
Jirajine
2020-08-03 20:51:21 +08:00
@reus 你觉得创建出来就是 nil,别人也可以觉得创建出来就得能用,不能是 nil 。
问题就在于它明明可以在编译时检查避免访问未初始化变量,却偏要自作聪明的默认给一个“零值”作为初始值,这个“零值”有时候是想要的有时候不是。
访问 undefined 变量在脚本语言中是很普遍的一类问题,go 作为静态编译型语言完全可以编译时就避免这类问题却不这么做,所以说是糟粕之一。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/695208

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX