指针在什么情况下是惯用的?

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

When is a pointer idiomatic?

问题

我来自没有显式指针的语言,所以我真的不理解它们存在的意义(无意冒犯)。

问题在于,大部分时间我都不知道为什么要将指针传递给函数。我确实理解当你传递一个指针时,对变量的修改会在任何地方都生效,但这有什么意义呢?为什么不直接修改值并返回结果呢?

例如,http.HandlerFunc 是一个接收 http.ResponseWriter*http.Request 作为参数的函数。我读到接口实际上是指针(是这样吗?),但我不明白的是,为什么?

为什么我要得到一个写入器的指针?我并没有修改它,我只是向其中写入内容。而且,为什么我要得到一个请求的指针?我只是在执行像 request.FormValue() 这样的操作。

通过这些例子,我想要确定的问题是,“什么时候需要传递指针?”

目前,我做的方式是编写代码,尝试编译它,通过添加引用符号和星号来修复要求传递指针的错误,直到错误消失。然而,我感觉这个我半懂不懂的指针概念很快就会让我后悔的。

英文:

I come from languages which don't have explicit pointers, so I don't really understand the point of their existence (no pun intended).

The problem is that I have no idea, most of the time, why I am passing a pointer to a function. I do understand that when you pass in a pointer, modifications to the variable are done to the value everywhere, but what's the point? Why not just modify the value and return the result?

For example, http.HandlerFunc is a function that receives http.ResponseWriter and *http.Request as arguments. I have read that interfaces are in fact pointers (is that right?), but what I'm not getting is, why?

Why am I getting a pointer to a writer? I'm not modifying it, I'm merely writing to it. And, why am I getting a pointer to a request? I am doing stuff like request.FormValue().

What I'm trying to determine here, through these examples, is the answer to the question, "when do I need to pass in a pointer?"

The way I do it right now is to write my code, try to compile it, fix the errors that say I must pass in a pointer by adding an ampersand and asterisk, until the errors pass. However, I feel this half-understood concept of pointers is going to bite me in the backside some day very soon.

答案1

得分: 2

你可以将指针视为指向对象内存地址的值。与大多数数据结构相比,指针很小(比如8字节)。

很多时候,你会得到一个指向对象的指针,因为传递这8个字节比创建要传递的整个对象的副本要快得多。

对于一个请求对象来说,如果要复制请求下的所有内容(负载、头部等),与仅传递一个指向原始数据的指针相比,代价会非常高昂。

英文:

You can think of a pointer as a value that points to the memory address of an object. Pointers are small (say 8 bytes) compared to most data structures.

A lot of times you will get a pointer to an object because it is much faster to pass those 8 bytes than to create a copy of the entire object that you want to pass.

In the case of a Request object it would be very expensive to create a copy of everything under the request (the payload, headers, and whatnot) compared to just passing a pointer that has access to the original data.

答案2

得分: 1

指针,顾名思义,是指向内存中某个位置的变量。

在某些情况下,当复制整个对象的值是不合理的时候,你可以使用指针。这可能是因为对象太大,复制它会很慢,所以你只想传递一个指向对象的小指针,并在内存中使用同一个对象(这可能是为什么http.Request是一个指针的原因),或者因为你需要修改对其他代码中可能已经有引用的对象的现有引用。你可以查看net/http的代码(在这里:https://golang.org/src/net/http/)来了解原因。(实际上,对于任何Go标准库,如果你想了解为什么或者如何以某种方式完成某个操作,代码都是开放的。)

但这有点无关紧要,因为作为用户,你传递指针的原因是因为函数被定义为以指针作为参数。编写库的程序员决定使用指针的原因并不重要。你可以查阅Go文档,或者像你现在这样,只传递一个值,如果编译器报错了就修复它。

英文:

A pointer is, as the name suggests, a variable that points to a place in memory.

You use it when copying the entire value of the object is unreasonable for some reason. This can either be because an object is so large that copying it would be slow, so you want to just pass a small pointer to the object and use the same object in memory (probably the reason http.Request is a pointer), or because you need to modify an existing reference to an object that other places in your code might already have a reference to. You can look into the code for net/http here to see why. (In fact, for any Go standard library the code is a open if you want to look into why or how something is done a certain way.)

But that's kind of irrelevant, because as a user, the reason you're passing a pointer is because the function is defined to take a pointer as a parameter. What reason the programmer who wrote the library decided to use a pointer is doesn't matter. You can either look up the go doc, or you can do what you're doing, and just pass a value, and if the compiler complains fix it.

答案3

得分: -1

指针是一个很容易理解的概念,当你理解了它的工作原理之后,但在理解之前,它看起来确实很难和烦人,特别是在C语言中。有指针算术运算,指向指针的指针等等。

无论如何,如果你的库不强制使用指针,你就不需要使用指针,但是在函数之间传递变量和数据结构可能会将所有东西复制到另一个内存区域,因为函数的作用域。

在大多数语言中,值是按字面值传递的。这意味着当你将一个变量传递给一个函数或类时,它可能会被复制。

更多的内存消耗,还需要CPU时间来复制项目。对于复杂性来说并不好。

另一方面,像PHP这样的一些语言具有一些自动化功能,比如写时复制算法,当你将参数传递给函数时,它是按引用传递的,它只传递内存地址给函数,直到函数尝试写入这个变量时,它才会复制变量。

但是自动化也带来了一些成本。这里真正的关键是成本,Go试图尽可能快地运行,减少自动化,增加用户控制,但同时也试图保持安全和简单。不像C、C++那样让你感到羞愧。

在你的例子中,当你通过内存引用(指针)将http.ResponseWriter传递给任何函数时,你在这个函数内部对它进行写操作,它直接写入其中,没有特殊的算法或检查,如果没有类型不匹配等等。可能会有一些像垃圾回收器之类的检查,但它确实带来的好处大于成本。

另外,在PHP、Java中,对象是按它们的引用传递的,但语言只是隐藏了这种冗长性。

> 我读到接口实际上是指针

不完全正确,Interface{}是Go中的一个基本类型,所以每种类型都实现了接口类型,在这个观点上,它只是一种类型,所以称之为指针没有意义。
它给你带来了动态性,例如:如果你从一个数据结构不固定且不一致的源读取数据,结构可能随时改变,比如XML或JSON源。只需使用接口!你已经知道每种类型的祖先是接口,它将在运行时处理数据的底层结构/类型。

但你也可以使用接口这个术语来定义一个接口(像Java、C#、PHP等语言),并提供实现方法。当任何满足这些方法的结构体时,它自然地实现了接口。这种实现设计被称为鸭子类型,请阅读更多信息https://en.wikipedia.org/wiki/Duck_typing

英文:

Pointers are really easy concept when you are just understand how they are works, but before understanding it really looks hard and annoying stuff, especially in C. There are pointer arithmetic, pointer which points a pointer etc.

Anyway, you haven't to use pointers, if your library doesn't force you to use, but passing variables, data structures around the functions may copy all the things into another memory section because of the function scope.

In most of the languages values are passes by literals. It means when you pass a variable to a function or class, it probably copy it.

More memory consumption, also needs CPU time to copy items. Not good for complexity.

On the other hand some languages like PHP has some automation, like copy on write algorithm when you pass a parameter to a function it passes by reference, it passes just memory address to function until function attempts to write to this variable, in that time it just copies the variable.

But automation also brings some costs. The real point here cost Go tries to be fast as possible less automation more user control but also tries to be safe and simple. Not like C, C++ it doesn't make you feel ashamed.

In your example http.ResponseWriter when you pass this to the any function by its memory reference(as a pointer) you write things to it inside this function, it just directly writes to it, there is no special algorithm or check if there is no type mismatch etc. there may some check like garbage collector but It really brings advantages than it costs.

Also in PHP, Java objects are passes by their references but the language just hides this verbosity.

> I have read that interfaces are in fact pointers

Not exactly, Interface{} Is a base type in Go so every type implements interface type, in this point of view it is just a type so there is no meaning to call as a pointer.
It gives you a dynamism, for example : if you read from a source which the data has not structured and inconsistent, structure can change any time e.g XML or JSON source. Just use Interface! you already know every type's ancestor is the Interface it will just handle underlying structure/type of data in runtime.

But also you can use Interface term to define an interface (like java, c#, php etc.) and put implementation methods. When any of the struct which satisfies these methods. It naturally implements the interface. This implementation design called as Duck Typing please read for further information https://en.wikipedia.org/wiki/Duck_typing

huangapple
  • 本文由 发表于 2016年1月26日 03:02:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/35000292.html
匿名

发表评论

匿名网友

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

确定