初始化结构体为指针的目的是什么?

huangapple go评论83阅读模式
英文:

What's purpose of initializing a struct as a pointer?

问题

在这段代码中,声明defaultOptions为指针并在后面对其进行解引用复制的目的是为了确保复制的是结构体的值而不是结构体本身的引用。这样做是为了避免在修改optCopy时同时修改defaultOptions的情况发生。

如果你将defaultOptions声明为非指针类型,并直接将其赋值给optCopy,那么optCopy将只是defaultOptions的一个引用,而不是一个独立的副本。这意味着当你修改optCopy时,defaultOptions也会被修改,因为它们指向同一个内存地址。

通过使用指针和解引用操作符*,你可以确保将defaultOptions的值复制到一个新的内存地址中,从而创建一个独立的副本。这样,当你修改optCopy时,defaultOptions的值不会受到影响。

因此,在这段代码中,使用指针和解引用操作符是为了确保复制的是结构体的值而不是引用,从而避免副作用和意外修改。

英文:

Zap initializes its default option struct as follows in its grpc interceptor:

var (
	defaultOptions = &options{
		levelFunc:       DefaultCodeToLevel,
		shouldLog:       grpc_logging.DefaultDeciderMethod,
		codeFunc:        grpc_logging.DefaultErrorToCode,
		durationFunc:    DefaultDurationToField,
		messageFunc:     DefaultMessageProducer,
		timestampFormat: time.RFC3339,
	}
)

And the later zap performs a copy of values:

*optCopy = *defaultOptions

What is the purpose of declaring the variable defaultOptions as a pointer and then later dereferencing it for copying? I was wondering if there is any issue with not using pointer:

   defaultOptions = options{
		levelFunc:       DefaultCodeToLevel,
		shouldLog:       grpc_logging.DefaultDeciderMethod,
		codeFunc:        grpc_logging.DefaultErrorToCode,
		durationFunc:    DefaultDurationToField,
		messageFunc:     DefaultMessageProducer,
		timestampFormat: time.RFC3339,
	}

    optCopy = &options{}
    *optCopy = defaultOptions
   

答案1

得分: 2

根据我之前在大型系统中遇到的问题,我猜测使用配置结构体时,如果由于某种原因软件的某个部分更改了某个值,这个更改将传播到具有该指针的任何函数/成员,而大多数情况下你不希望发生这种情况,通常你希望从文件中读取的配置保持不变,即使某个函数需要对保存该配置的结构体的特定字段进行转换。

因此,基本上你保持原始结构体的新鲜度,但可以发送指针以将其内容复制到任何地方。
这是我根据经验得出的猜测,很可能是应用程序架构决策。

编辑:经过进一步思考:
如果代码的作者在他的代码中考虑到将该数据结构移动到代码的各个层次和广度中,将其声明为值意味着每次他想要将数据从一个函数移动到另一个函数时都必须复制它,或者数据结构可能会在作用域执行结束时被擦除,而使用指针,他可以只移动指针(速度更快),然后在指针到达目标函数时只复制数据一次。

英文:

My guess, based on previous issues I had with big systems, is that with configuration structs, if for any reason some part of your software changes the value of something, that change will propagate to any function/member who has that pointer, and most of the times you don't want that to happen, you usually want that the configuration that you probably read from a file, stays the same, even if some function needs to do a transformation of a specific field of the struct holding that configuration.

So basically, you keep the original struct fresh, but you can send the pointer around to have its contents copied anywhere.
That's my educated guess, it is most likely an application architecture decision.

Edit: After further pondering:
If the author of the code had in his mind the idea of moving that data structure everywhere in his code, in multiple levels deep and broad, declaring it as value would mean he would have to copy it every time he wanted to move the data from function to function, or that the data structure could be erased by the end of execution of scope, whereas with a pointer he can move only the pointer around (much faster) and then only copy the data once the pointer arrives at the destination function.

答案2

得分: 2

使用指针的一个可能优势是你可以将指针设置为nil;显然,如果它是nil,你就不能对其进行解引用;但这可能用于指示没有选项,并且可能有代码来处理这种情况。

注意:我不是Go程序员。

英文:

A possible advantage with using a pointer is that you can then have that pointer set to nil; obviously if it is nil, you can't dereference it; but this might be used to indicate that there are no options and there may be code to handle this.

Caveat: I am not a Go programmer.

huangapple
  • 本文由 发表于 2022年8月19日 05:40:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/73409733.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定