Explore objects in Go (object)

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed. [] (https://raw.githubusercontent.com/studygolang/gctt-images/master/go-object/goexplorer.png) When I accept go there's no object at all After that, I began to understand more easily what the Go object is, in fact, a collection of functions that can operate in a common state, with the addition of a bit of syntactic sugar embellishment. You might be thinking, "Shut up, go, of course there's an object," or "a collection of functions that can manipulate a common state is the definition of object." Well, maybe you're right. At least as far as I can think of an object I've used before, I don't see a set of related functions that operate in the same state, and what's the difference between an object. Besides, Go's object model is more than just syntactic sugar (I'm talking about a bit of extreme:-)). But the object model is quite different from the model of the classic, such as Java,c++ and Python (which I know so much about so far). I benefited a lot from trying to find out how the object of Go works, abandoning the traditional concept of object and thinking only of the function. All I have to do is try to compose the object model into a function and reconstruct it, and see how go works, as you can see, go is more inclined to use object as a helper to make the syntax simpler, rather than object-oriented language, anything is object. The deconstruction below may not look very good, because I am not proficient in Go, but I still force myself to try, because it looks like a fun:-). # # From the beginning of the function, I try to start from the function, the following is a slightly stupid example to see what can be done with the function. Let's define a type, which is actually a function: "' Gotype Adder func (int, int) int '" You can think of this as a interface (but they're not the same thing). Any function that conforms to this feature can be treated as a **adder** type: ' ' go//same type as Adderfunc add (a int, b int) int {return a + B} ' ' An abstract Adder that does not know how to add : "' Gofunc abstractedadd (a Adder, b int, c int) int {return A (b, c)} '" This really reminds me that I can do something similar with interface. **abstractedadd** does not know how to do add, but he can accept any Adder implementation that follows the same protocol. Here is the most useless and simplest example, all code: "' Gopackage mainimport" FMT "type Adder func (int, int) int//same type as Adderfunc add (a int, b int ) int {return a + B}func Abstractedadd (a Adder, b int, c int) int {return A (b, c)}func main () {var a adderfmt.printf ("Adde R:%v\n ", a) a = addfmt. Printf ("Adder initialized:%v\n", a) fmt. Printf ("%d +%d =%d\n", 1, 1, Abstractedadd (A, 1, 1)) fmt. Printf ("%d +%d =%d\n", 1, 1, Abstractedadd (Add, 1, 1))} "" From this example we explore the next object of Go. Can a method conform to the **adder** type? In your experience it might be a bit counterintuitive (as if you needed a function, and actually given a method, that means), let's look at Adder object. ' ' ' Gotype objectadder struct{}func (o *objectadder) Add (a int, b int) int {return a + B} ' ' Looks right, added to our example: ' ' Gopackage mai Nimport "FMT" type Adder func (int, int) intfunc Add (a int, b int) int {return a + B}func Abstractedadd (a Adder, b int, C in T) int {return A (b, c)}type Objectadder struct{}func (o *objectadder) Add (a int, b int) int {return a + B}func main () {var A adderfmt.printf ("Adder:%v\n", a) a = Addfmt. Printf ("Adder initialized:%v\n", a) fmt. Printf ("Func:%d +%d =%d\n", 1, 1, Abstractedadd (A, 1, 1)) fmt. Printf ("Func:%d +%d =%d\n", 1, 1, Abstractedadd (Add, 1, 1)) var o *objectadderfmt.printf ("object:%d +%d =%d\n", 1, 1, Abstractedadd (O.add, 1, 1)} ' results output: ' ' Adder: <nil>adder initialized:0x401000func:1 + 1 = 2func:1 + 1 = 2object: 1 + 1 = 2 "ha, successful. Unlike interfaces, function signatures do not match any method names, and you can pass methods like arguments, because the method is actually a function, somewhat like this: "' Govar o *objectadderfmt.printf (" object:%d +%d =%d\n ", 1, 1 , Abstractedadd (O.whatever, 1, 1) "should be able to run. Doesn't it look like a method is a function? Look at this again: "' gofmt. Printf ("func Add:%t\n", add) fmt. Printf ("object. ADD:%t\n ", O.add) ' ' Results output: ' ' func add:func (int, int) intobject. Add:func (int, int) int "" Do you see the difference between this empty function and this object method? No, because there is no difference. This is why the pass parameter can be run. This can also explain another problem in the code that makes it easy for beginners (like me) to learn to Go. We did not fully initialize the Objectadder in the example. I use pointers for purposes, and you can see that pointers are not initialized (nil), but the code works. In other object-oriented languages I know, it's impossible to run, but in Go, why? That's because in Go, there is no method, no method type, and the method is actually a syntactic sugar, which is used to pass an instance type as the first parameter (as used in the C language) when making a function call. The first parameter type in Go is usually called the method receiver, but this does notWhat is special is a parameter passed to the function. Refine our example below: "' gofmt. Printf ("Objectadder.add:%t\n", (*objectadder). ADD) fmt. Printf ("Objectadder.add:%d +%d =%d\n", 1, 1, (*objectadder). ADD (Nil, 1, 1)) "' What have I done here? ' is to figure out what the Go actually did when you made the following statement: "' Gotype objectadder struct{}func (o *objectadder) Add (a int, b int) int {} '" in this gives ***objectadd A function has been added to the er** type. This function can be accessed and can be used as any value (called, passed as a parameter, etc.). If you think "Hi, objectadder type is not \*objectadder", OK, in Go the pointer type is really another type, even a pointer with a function combination is not a type. Which type of function to add is determined by the method receiver, in this case (\*objectadder). This is related to the concept of Go [method set] (https://github.com/golang/go/wiki/MethodSets). Anyway, keep looking down, the output: ' ' ObjectAdder.Add:func (*main. Objectadder, int, int) intobjectadder.add:1 + 1 = 2 "' There is no method at all, just a function. The object we see in Go is some combination of functions associated to a certain type, with a little bit of syntactic sugar, to pass the first argument to you. To be honest, it's like all object-oriented objects actually implement the same. The advantage is that in Go this is 100% concise and clear, no magic, is the grammatical sugar. Go is really rigorous about simplicity. So many things are simpler and more consistent, as can be seen in the example. There is no difference between a function or a method of making a parameter (I can't think of a reason for the difference). The following is the final example of all the code: "' Gopackage mainimport" FMT "type Adder func (int, int) int//same type as Adderfunc add (a int, b int) int {R Eturn A + b}func abstractedAdd (a Adder, b int, c int) int {return A (b, c)}type Objectadder struct{}func (o *objectadder) Add (a int, b int) int {retur n A + b}func main () {var a adderfmt.printf ("Adder:%v\n", a) a = addfmt. Printf ("Adder initialized:%v\n", a) fmt. Printf ("Func:%d +%d =%d\n", 1, 1, Abstractedadd (A, 1, 1)) fmt. Printf ("Func:%d +%d =%d\n", 1, 1, Abstractedadd (Add, 1, 1)) var o *objectadderfmt.printf ("func Add:%t\n", add) fmt. Printf ("object. ADD:%t\n ", O.add) fmt. Printf ("object:%d +%d =%d\n", 1, 1, Abstractedadd (O.add, 1, 1)) fmt. Printf ("Objectadder.add:%t\n", (*objectadder). ADD) fmt. Printf ("Objectadder.add:%d +%d =%d\n", 1, 1, (*objectadder). ADD (Nil, 1, 1)} "This example is completely state-independent. Object usually has state and side effects, Go function also has state and side effect? # # function and Status # #为了让函数和 the gap between objects is smaller, we use a primitive/simplest example, a iterator: ' Gopackage mainimport ' FMT ' func iterator () func () int {A : = 0return func () int {A++return A}}func main () {iter: = iterator () fmt. Printf ("ITER 1:%d\n", ITER ()) FMT. Printf ("ITER 2:%d\n", ITER ()) FMT. Printf ("ITER 3:%d\n", ITER ())} "If you run it, you will see that the iterator is valid. Exactly what do we have now? We have a **iterator** function that looks like the constructor of another function, and it returns this function, which is why **iterator** returns the type: "' Gofunc () int '" is usually referred to as the syntax structure of the closure: "' Goa: = 0return func () int {A++return A} "the function that we instantiate uses an external variable that associates the variable **a** with the newly created function, which contains a **a** reference and can be manipulated (**a**). If you are accustomed to using object as a form of state management (in fact many C programmers also find it strange, because the function is statically constructed in C), this is a bit more brain-burning. In the Go language, functions can be initialized at any time, and the following is another version of this example, which shows that we are actually initializing the function: "' Gopackage mainimport" FMT "Func iterator () func () int {A: = 0return func () I NT {A++return A}}func main () {itera: = iterator () Iterb: = iterator () fmt. Printf ("Itera 1:%d\n", Itera ()) fmt. Printf ("Itera 2:%d\n", Itera ()) fmt. Printf ("Itera 3:%d\n", Itera ()) fmt. Printf ("Iterb 1:%d\n", Iterb ()) fmt. Printf ("Iterb 2:%d\n", Iterb ()) fmt. Printf ("Iterb 3:%d\n", Iterb ())} "Gets the result: ' Itera 1:1itera 2:2itera 3:3iterb 1:1iterb 2:2iterb 3:3" ' so each iterator Are independent, there is no way for a function to get state from another function, unless explicitly allowed in the code, or you can do a bad pointer operation with an unsafe package. This is interesting because languages like Lisp initially have closures that provide the absolute maximum amount of encapsulation you can imagine. You have no other way to get the state directly except from the function. Let's take a look at the closure of the object with Go: "' GopackagE mainimport "FMT" type iterator struct {a int}func (I *iterator) iter () int {I.a++return I.a}func newiter () *iterator {ret Urn &iterator{a:0,}}func Main () {i: = Newiter () fmt. Printf ("ITER 1:%d\n", I.iter ()) fmt. Printf ("ITER 2:%d\n", I.iter ()) fmt. Printf ("ITER 3:%d\n", I.iter ())} "can see that very simple things, in the way of object will appear more awkward, at least in my opinion." I even used a similarly bad int variable named **a**, which actually represents the state. Now we create a struct, save the state, add a type to the function, and use this function to control the state. If you feel complex, you can also use struct: "' gopackage mainimport" FMT "type iterator IntFunc (i *iterator) iter () int {*i++return int (*i)}fun C Main () {var i iteratorfmt. Printf ("ITER 1:%d\n", I.iter ()) fmt. Printf ("ITER 2:%d\n", I.iter ()) fmt. Printf ("ITER 3:%d\n", I.iter ())} "This function also does the same thing in a different way." As with object, you can manage states and isolate states with scopes, and only functions can modify this state. To accomplish this, we write several functions that manipulate a shared state (which is what object does): "Go package Mainimport" FMT "type Statechanger func () IntFunc new () ( Statechanger, Statechanger) {A: = 0return func () int {A++return a},func () int {A--return A}}func main () {inc, Dec: = new () Fmt. PRINTF ("Inc 1:%d\n", Inc ()) FMT. PrINTF ("Inc 2:%d\n", Inc ()) FMT. Printf ("Inc 3:%d\n", Inc ()) FMT. Printf ("Dec 1:%d\n", Dec ()) FMT. Printf ("Dec 2:%d\n", Dec ()) FMT. Printf ("Dec 3:%d\n", Dec ())} ' output: ' ' inc 1:1inc 2:2inc 3:3dec 1:2dec 2:1dec 3:0 ' ' can be seen clearly that two functions share the same state and can manage the state as if you were using a two The object of a method. Of course, I'm not encouraging you to use a function with some variables, the existence of a struct is to give meaning to the names of different types of combinations. As with functions, only a bunch of loose functions are very bad in most cases (such as with data). Because Go does use functions as first-class citizens, there are many fields in the struct that contain functions that simulate the behavior of a method to represent a set of functions that operate in a common state. However, this is difficult and error-prone, such as the possibility of calling uninitialized fields/methods (anyone with C code can understand the problem and the consequences). A calendar operation: ' Gopackage mainimport ' fmt ' type Calculator struct {Add func (int,int) intsub func (int,int) Int}func Newcalculator () Calculator {return calculator{add:func (a int, b int) int {return a + b},sub:func (a int, b int) int {Retu RN A-b},}}func Main () {calc: = Newcalculator () fmt. Println (Calc. ADD (3, 2)) fmt. Println (Calc. Sub (3, 2)} "Well, you can argue that the code cumbersome the problem, and in your experience it might be better than the Go-to-use approach. But you can't deny that it leaves a lot of room for mistakes. For example, the following: "' Gopackage mainimport" fmt "type Calculator struct {Add func (int,int) intsub func (int,int) Int}func Newcalculator () CAlculator {return Calculator{add:func (a int, b int) int {return a + b},sub:func (a int, b int) int {return A-b},}}func Main () {var calc calculatorfmt.println (Calc. ADD (3, 2)) fmt. Println (Calc. Sub (3, 2)} ' output is: ' ' panic:runtime error:invalid memory address or nil pointer dereference[signal sigsegv:segmentatio N violation code=0xffffffff addr=0x0 pc=0xc64e8]goroutine 1 [Running]:main.main ()/tmp/sandbox772959961/main.go:23 + 0x28 "Although this problem may also occur with the use of methods, it is much safer to add a function to a type than to represent the same type of function combination operation. At least the calling method is always safe (of course you may also encounter an invalid method recipient that causes the program to crash). In addition to the tedious and error-prone, there is a problem of how to express abstract concepts, which is more complex than the individual functions. # # Abstract All our current abstract methods are made up of a function, a function can be represented, but what if there are more abstract requirements than a function? If there is no way to express it, you can only combine abstract operations in one function, which is scary (imagine Read/write abstract model in the same function). The above Calculator example provides a way to simulate a method, to the extent that people see how to use the calculator when they do not see that the method is actually not a method at all. But there's an important concept out there, a very basic concept in the go approach, how do you say you need a set of functions that don't have to define who to implement or how? In the whole, given a function x, which requires a set of function y, how do you express the syntax of a Z-type to implement this set of required Y-functions, so that it can be used as a feasible method of the X function? One solution is to use * * Security polymorphic. I want to have a number of different implementations of functions that seamlessly interact with the same group. The focus of polymorphism is on * * security. I share my opinion on the polymorphism of C, the polymorphism of C is feasible, and it works well, but it is absolutely unsafe. You might be against saying no.The implementation is absolutely secure, but at least more secure than C, which is what most languages like Java and Python did at the beginning of development. Security is important because the calculator example may be used to implement this form. We can do this: "' Gotype Calculator struct {Add func (int,int) intsub func (int,int) Int}func Codethatdependsoncalculator (c Calculator) {//etc} ' this will allow a **calculator** of N different implementations to integrate with code that relies on it, but is not secure. Very simple, only half of the implementation can be cheat. All functions that receive **calculator** must check that **add** and **sub** are not nil. This is too similar to what is implemented in C, which is obviously what the compiler can do for you (in C you can define it with a macro). The go solution is to interface, which in my opinion is the best feature of Go. Since this blog post has been very long, I will discuss the evolution of the idea of interface in the following blog post. Have a good time exploring the Go process;-). # # Thanks Special thanks:-[i4k] (https://github.com/tiago4orion)-[Vitorarins] (https://github.com/vitorarins)-[Cadicallegari] ( Https://github.com/cadicallegari) Thank you for taking the time to help me review and point out some of the low-level mistakes.

via:https://katcipis.github.io/blog/exploring-go-objects/

Author: TIAGO Katcipis Translator: arisaries proofreading: polaris1119

This article by GCTT original compilation, go language Chinese network honor launches

This article was originally translated by GCTT and the Go Language Chinese network. Also want to join the ranks of translators, for open source to do some of their own contribution? Welcome to join Gctt!
Translation work and translations are published only for the purpose of learning and communication, translation work in accordance with the provisions of the CC-BY-NC-SA agreement, if our work has violated your interests, please contact us promptly.
Welcome to the CC-BY-NC-SA agreement, please mark and keep the original/translation link and author/translator information in the text.
The article only represents the author's knowledge and views, if there are different points of view, please line up downstairs to spit groove

1423 Reads
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.