Object-oriented programming language go based on type system

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

(organized from the network)

Object-Oriented Programming

The go language's object-oriented programming (OOP) is simple and elegant. The simplicity of it is that it does not have many concepts in oop, such as inheritance, virtual functions, constructors and destructors, hidden this pointers, and so on. To say it is elegant, is that its object-oriented (OOP) is a natural part of the language type system. The entire type system is connected through an interface (interface), seamless.

Type System

There are few programming class books that talk about the type system. But the fact that the type system is the support of the entire language is crucial.

A type system is a type system diagram for a language. In the entire type system diagram, include the contents:

    • Basic type. such as Byte, int, bool, float, and so on.
    • The composite type. Array, struct (struct), pointer (pointer), and so on.
    • Any type. That is, the type that can point to any object.
    • Value semantics and referential semantics.
    • Object-oriented. That is, all types that have object-oriented features, such as member methods.
    • Interface (interface).

The type system describes how the content is associated in a language. Like we talk about the Java type System: In the Java language, there are two completely separate types of systems, one set of value type systems, primarily basic types, such as Byte, int, Boolean, char, double, string, and so on, based on value semantics. The set is an object type system that is rooted with the object type, which can define member variables, member methods, and can have virtual functions. These types are based on referential semantics and allow only new to come out (on the heap only). Only instances in the object type system can be referenced by any type. The any type is the root--object type of the entire object type system. A value type that wants to be referenced by any type requires a boxed (Boxing) procedure, such as an int type that needs to be boxed into an integer type. Only types in the object type system can implement an interface (by allowing the type to inherit from the interface being implemented).

In the go language, most types are value semantics and can have methods. You can "add" new methods to any type (including built-in types) when needed. Implementing an interface (interface) does not have to inherit from the interface (in fact the go language does not inherit the syntax), but only implements all the methods required by that interface. Any type can be referenced by any type. The any type is an empty interface, i.e. interface{}.

Adding methods to Types

In the go language, you can add methods to any type, including built-in types, except pointer types, for example:

type Integer intfunc (a Integer) Less(b Integer) bool {    return a < b}

In this example, we define a new type integer, which is not fundamentally different from int, except that it adds a new method to the built-in int type: less. In this way, you can make the integer look like a class:

func main() {    var a Integer = 1    if a.Less(2) {        fmt.Println(a, "Less 2")    }}

When learning other languages, many beginners are very mysterious about object-oriented. When I introduce the object-oriented to beginners, I often say "object-oriented is just a syntactic sugar". The above code is written in a process-oriented way:

type Integer intfunc Integer_Less(a Integer, b Integer) bool {return a < b}func main() {var a Integer = 1if Integer_Less(a, 2) {    fmt.Println(a, "Less 2")}}

In the Go language, object-oriented mysteries are stripped out. Compare these two pieces of code:

func (a Integer) Less(b Integer) bool {  // 面向对象    return a < b}func Integer_Less(a Integer, b Integer) bool {  // 面向过程    return a < b}a.Less(2)  // 面向对象Integer_Less(a, 2)  // 面向过程

As you can see, object-oriented is simply a form of grammatical expression. There is no hidden this pointer in the go language. The meaning of this sentence is:

First, the target that the method imposes (that is, "object") is explicitly passed, not hidden.
Second, the target (i.e. "object") that the method imposes does not need to be a pointer, nor does it have to be called this.

We compare the code in the Java language:

class Integer {    private int val;    public boolean Less(Integer b) {        return this.val < b.val;    }}

This Java code beginner is difficult to understand, mainly because the less method of the integer class hides the first parameter integer* this. If you translate it into C code, it will be clearer:

struct Integer {    int val;};bool Integer_Less(Integer* this, Integer* b) {    return this->val < b->val;}

The object-oriented in the go language is the most intuitive and requires no additional cost. This can sometimes be an additional cost if the object must be passed as a pointer, because the object is sometimes small (such as 4 bytes), and it is not cost-effective to pass the pointer.

You must use a pointer only when you need to modify the object. It is not a go language constraint, but a natural constraint. As an example:

func (a *Integer) Add(b Integer) {    *a += b}

This adds the Add method to the integer type. Because the Add method needs to modify the value of the object, it needs to be referenced with a pointer. The call is as follows:

func main() {    var a Integer = 1a.Add(2)    fmt.Println("a =", a)}

The result of running the program is: A = 3. If you don't use pointers:

func (a Integer) Add(b Integer) {    a += b}

The result of running the program is: a = 1, that is, to maintain the original value. The reason for this is that, like go and C, types are based on value passing. To modify the value of a variable, you can only pass a pointer.

Value semantics and referential semantics

The difference between value semantics and referential semantics is the assignment of values:

b = ab.Modify()

If the modification of B does not affect the value of a, then this type belongs to the value type. If the value of a is affected, then this type is a reference type.

The types in most go languages, including:

    • Basic type. such as Byte, int, bool, float32, Float64, String, and so on.
    • The composite type. Array, struct (struct), pointer (pointer), and so on.

are based on value semantics. The value semantics of the type in the go language are very thorough. We say this because of the array. If you have studied C, you will know that arrays in C are more specific. Passing an array by function is based on referential semantics, but when an array variable is defined in a struct, it is the value semantics (represented by the structure assignment, the array is completely copied to a new copy).

There is no difference between an array and a primitive type in the go language, which is a purely value type. For example:

var a = [3]int{1, 2, 3}var b = ab[1]++fmt.Println(a, b)

Program run Result: [1 2 3] [1 3 3]. This indicates that the B = A assignment statement is a full copy of the array contents. To express a reference, you need to use the pointer:

var a = [3]int{1, 2, 3}var b = &ab[1]++fmt.Println(a, *b)

Program run Result: [1 3 3] [1 3 3]. This indicates that the B=&a assignment statement is a reference to the contents of the array. The type of variable B is not [3]int, but *[3]int type.

There are 4 types in the go language that are more specific and look like reference types:

    • Slice (slice): an interval that points to an array.
    • Dictionary (map): A very common data structure that provides Key-value query capabilities.
    • Channel (CHAN): Communication facility between the Executive Body (goroutine).
    • Interface (interface): An abstraction of a set of types that satisfy a contract.

But this does not affect the nature of the Go language type as the value semantics. Let's take a look at these types:

Slices (slice) are essentially range, and you can roughly represent []t as:

type slice struct {    first *T    last *T    end *T}

Because the inside of a slice (slice) is a series of pointers, it is not surprising that you can change the elements of the array you are pointing to. The assignment of the slice type itself is still a value semantics.

The dictionary (map) is essentially a dictionary pointer, and you can roughly represent Map[k]v as:

type Map_K_V struct {    ...}type map[K]V struct {    impl *Map_K_V}

Based on pointers (pointer), we can completely customize a reference type, such as:

type IntegerRef struct { impl *int }

The Channel (Chan) is similar to a dictionary (map) and is essentially a pointer. Why they are designed to be reference types rather than uniform value types is because a full copy of a channel (Chan) or dictionary (map) is not a regular requirement.

Similarly, the interface (interface) has referential semantics because it maintains two pointers internally. The signal is:

type interface struct {    data *void    itab *Itab}

The position of the interface in the go language is very important. With regard to the internal implementation details of the interface (interface), later in the high-level topic, we will analyze it carefully.

struct (struct)

The Go language structure (struct) has the same status as the class of other languages. But the go language abandons a large number of OOP features, including inheritance, and retains only the most basic features of the combination (compose).

Combination (compose) is not even a feature of OOP. Because in a procedural programming language such as the C language, there are also structures (structs), and there are combinations (compose). A combination is just the basis for forming a composite type.

As we said above, all the types of Go languages (except pointer types) can have their own methods. In this context, the structure of the Go Language (struct) is just a very common composite type, bland. For example, we want to define a rectangular type:

type Rect struct {    x, y float64    width, height float64}

We then define the method area to calculate the square of the rectangle:

func (r *Rect) Area() float64 {    return r.width * r.height}

Initialization

After defining the Rect type, how do we create and initialize an object instance of the Rect type? There are the following methods:

rect1 := new(Rect)rect2 := &Rect{}rect3 := &Rect{0, 0, 100, 200}rect4 := &Rect{width: 100, height: 200}

In the go language, a variable that is not explicitly initialized is initialized to a value of 0 for that type (for example, a 0 value of type bool is false, a value of 0 is 0 for an int type, and an empty string for a string type 0 value).

constructor function? No need. In the go language you only need to define a normal function, which is usually named Newxxx, which means "constructor":

Func newrect (x, y, width, height float64) *rect {
Return &rect{x, y, width, height}
}

It's all very natural and there's nothing to be abrupt about.

Anonymous combination

To be exact, the go language also provides inheritance, but employs a combination of grammars, which we call anonymous combinations:

type Base struct {    ...}func (base *Base) Foo() { ... }func (base *Base) Bar() { ... }type Foo struct {    Base    ...}func (foo *Foo) Bar() {    foo.Base.Bar()    ...}

The code above defines a base class (which implements Foo, bar two member methods), then defines a Foo class, inherits from base and implements a rewrite of the bar method, which first invokes the base class Bar method.

When the derived class Foo does not overwrite the member method of base class base, the corresponding method is "inherited". For example, in the example above, call Foo. Foo () and call Foo. The Base.foo () effect is the same.

Unlike other languages, the go language clearly tells you how a class's memory layout is. In the go language you can also modify the memory layout as you like:

type Foo struct {...    Base}

This code is semantically different from the example above, but the memory layout has changed. The data for base class base is placed at the end of the "derived class" Foo.

Also, in the go language you can "derive" from a class as a pointer:

type Foo struct {    *Base    ...}

The go code still has a "derivation" effect, but when Foo creates an instance, it needs to provide a pointer to the base class instance externally. There is a similar function in C + +, which is the virtual base class. But the virtual base class is a very difficult feature to understand, generally speaking, C + + developers will forget this feature.

Accessibility of Members

The go language is very stingy with the addition of keywords. There are no keywords such as private, protected, public in the Go language. To think that a symbol can be accessed by another package, you need to define the symbol to start with a capital letter. Such as:

type Rect struct {    X, Y float64    Width, Height float64}

Thus, the member variables of the RECT type are all public. The member methods follow the same rules, such as:

func (r *Rect) area() float64 {    return r.Width * r.Height}

In this way, the area method of rect can only be used within the package in which the type resides.

One thing to emphasize is that the accessibility of symbols in the Go language is package-level, not class-level. Although the area is an internal method of rect, it can be accessed by other types in the same package. This kind of accessibility control is very rough, very special, but very practical. If the accessibility of the Go language symbol is class-level, you need to add a keyword like friend to indicate that two classes are friends and can access private members.

Interface (interface)

Rob Pike once said that if only one feature of the go language could be ported to another language, he would choose the interface.

Interface (interface) plays a critical role in the go language. If Goroutine and channel are the cornerstone of the concurrency model that supports the go language, the go language becomes a very beautiful landscape in today's clustering and multicore era, and the interface (interface) is the cornerstone of the go language's entire type system, Let go language in the Basic programming philosophy of exploration, to achieve a history without precedent height.

I have said on several occasions that the go language is a transformational faction, not an improvement, in programming philosophy. This is not because the go language has goroutine and channel, but more importantly because of the go language type system, because the go language interface. Because of the interface, the Go Language programming philosophy becomes perfect.

The Go Language Interface (interface) is more than just an interface.

Why do you say that? Let us take a careful way.

Interfaces for other languages (c++/java/c#)

The interface of the go language is not the interface that you previously touched in other languages (c++/java/c#, etc.).

The interface before the Go Language (interface), mainly as a contract between different components exist. The implementation of the contract is mandatory, and you must declare that you did implement the interface. In order to implement an interface, you need to inherit from the interface:

interface IFoo {    void Bar();}class Foo implements IFoo { // Java 文法    ...}

"' C + +
Class Foo:public IFoo {//C + + grammar
...
}

ifoo* foo = new Foo;
```

Even if there is an identical interface, but the name is different called IFoo2 (the same name but in different namespaces, but also the name is different), the above class Foo only implemented the IFoo, but did not implement IFoo2.

This type of interface (interface), which we call an intrusive interface. The main manifestation of "intrusive" is that the implementation class needs to explicitly declare that it implements an interface.

This mandatory interface inheritance is a major mistake in the development of object-oriented programming (OOP) thinking. I say this because it is fundamentally against the causal relationship of things.

Let's start with the process of contract formation. Imagine that we are now implementing a simple search engine (SE). The search engine relies on two modules, one for the hash table (HT) and one for the HTML parser (Htmlparser).

The implementation of the search engine believes that SE's reliance on the hash table (HT) is deterministic, so he does not think it is necessary to define an interface between SE and HT, but rather uses HT in a direct import (or include), whereas the dependency of module SE on htmlparser is indeterminate, The future may need to have wordparser, Pdfparser and other modules to replace the Htmlparser to meet different business requirements. To do this, he defines the interface between SE and Htmlparser, and indirectly references the module htmlparser in module SE through the interface invocation method.

It should be noted that the demand side of the interface (interface) is the search engine (SE). Only SE knows what the interface should be defined to be more reasonable. But the implementation side of the interface is Htmlparser. Based on the principle of one-way dependency of module design, when the module Htmlparser realizes its own business, it should not care about the requirements of a specific user. Htmlparser in the realization of the time, and even do not know the future SE will use it someday. It is unreasonable to ask the module htmlparser to know all of its required parties and to declare in advance that the interfaces are implemented. The same goes for the search engine (SE) itself. SE is not able to anticipate what needs will be needed in the future and implement the interfaces they require.

This problem becomes more prominent in the provision of the standard library. For example, we implement the file class (here we use the grammar of the Go language to describe the method to be implemented, ignoring the grammatical details), and it has these methods:

Read(buf []byte) (n int, err error)Write(buf []byte) (n int, err error)Seek(off int64, whence int) (pos int64, err error)Close() error

So, should you define a ifile interface, or should you define a series of Ireader, Iwriter, Iseeker, Icloser interfaces, and then let file inherit from them? Apart from the actual user scenario, it is not meaningful to discuss which of these two designs is better. The problem is, when implementing the file class, how do I know how the external will use it?

Because of this unreasonable design, the Java, C # class Library each class implementation needs to tangle:

    • Question 1: What interfaces do I provide?
    • Question 2: If two classes implement the same interface, which package should I put the interface in?

Non-intrusive interface

In the go language, a class only needs to implement all the functions required by the interface, then we say that this class implements the interface. For example:

type File struct {    ...}func (f *File) Read(buf []byte) (n int, err error)func (f *File) Write(buf []byte) (n int, err error)func (f *File) Seek(off int64, whence int) (pos int64, err error)func (f *File) Close() error

Here we define a file class, and implement methods such as Read,write,seek,close. Imagine that we have the following interfaces:

type IFile interface {    Read(buf []byte) (n int, err error)    Write(buf []byte) (n int, err error)    Seek(off int64, whence int) (pos int64, err error)    Close() error}type IReader interface {    Read(buf []byte) (n int, err error)}type IWriter interface {    Write(buf []byte) (n int, err error)}type ICloser interface {    Close() error}

Although the file class does not inherit from these interfaces, it can even be unaware of the existence of these interfaces, but the file class implements these interfaces and can be assigned values:

var file1 IFile = new(File)var file2 IReader = new(File)var file3 IWriter = new(File)var file4 ICloser = new(File)

The non-intrusive interface of the go language seems to be just a small grammatical adjustment, but it has far-reaching implications.

First, the Go Language standard library, no longer need to draw the class Library inheritance tree diagram. You must have seen many inheritance tree diagrams for C + +, Java, C # class libraries. Here is a Java Inheritance Tree graph:

Http://docs.oracle.com/javase/1.4.2/docs/api/overview-tree.html

In go, the inheritance tree of a class has no meaning. You just need to know what methods this class implements, and what each method means is enough.

Second, when implementing a class, just care about what you should provide. No need to tangle up the interface needs to be more thin to be reasonable. Interfaces are defined by the consumer on demand, without prior planning.

Thirdly, it is not recommended to import a package in order to implement an interface, but simply to refer to the definition of one of the interface. Because multiple references to an external package means more coupling. The interface is defined by the consumer in terms of its own requirements, and the consumer does not have to care if other modules have defined similar interfaces.

Interface Assignment Value

The assignment of the interface (interface) is divided into the following 2 scenarios in the Go language:

    • Assigning an object instance to an interface
    • Assigning an interface to another interface

The assignment of an object instance of some type to an interface is discussed first. This requires that the object instance implement all the methods required by the interface. For example, we have implemented an integer type before, as follows:

type Integer intfunc (a Integer) Less(b Integer) bool {    return a < b}func (a *Integer) Add(b Integer) {    *a += b}

Accordingly, we define the interface Lessadder as follows:

type LessAdder interface {    Less(b Integer) bool    Add(b Integer)}

Now there is a problem: Suppose we define an object instance of an integer type, how is it assigned to the Lessadder interface? Should I use the following statement (1) or a statement (2)?

var a Integer = 1var b LessAdder = &a     ... (1)var b LessAdder = a      ... (2)

The answer is that the statement (1) should be used. The reason is that the go language can be based on

func (a Integer) Less(b Integer) bool

This function automatically generates a new less method:

func (a *Integer) Less(b Integer) bool {    return (*a).Less(b)}

Thus, the type *integer has both the less method and the Add method to satisfy the Lessadder interface. And on the other hand, according to

func (a *Integer) Add(b Integer)

This function cannot be generated automatically

func (a Integer) Add(b Integer) {    (&a).Add(b)}

Because (&a). Add changes only the function parameter a, which has no effect on the object that is actually being manipulated externally, which does not conform to the user's expectations. Therefore, the go language does not automatically generate this function for it. Therefore, the type integer only has the less method, lacks the Add method, does not satisfy the Lessadder interface, therefore the above statement (2) cannot assign the value.

To further prove the reasoning above, we may as well define a lesser interface as follows:

type Lesser interface {    Less(b Integer) bool}

We then define an object instance of type integer and assign it to the lesser interface:

var a Integer = 1var b1 Lesser = &a     ... (1)var b2 Lesser = a      ... (2)

As we expected, both the statement (1) and the statement (2) can be compiled and passed.

Let's talk about another scenario: assigning an interface to another interface. In the go language, as long as two interfaces have the same method list (it doesn't matter if the order is different), then they are equivalent and can be assigned to each other. For example:

package onetype ReadWriter interface {    Read(buf []byte) (n int, err error)    Write(buf []byte) (n int, err error)}
package twotype IStream interface {    Write(buf []byte) (n int, err error)    Read(buf []byte) (n int, err error)}

Here we have defined two interfaces, one called A. Readwriter, one called the other. IStream. Both define the read and write methods, just the opposite of the defined order. One. Readwriter first defines read and then defines write, and the second. IStream instead.

In the go language, these two interfaces are actually no different. Because:

    • Any implementation of one. The class of the Readwriter interface is implemented in both. IStream.
    • any one. The Readwriter interface object can be assigned to Two.istream, and vice versa.
    • Use one anywhere. Readwriter interface, and use both. There is no difference in IStream.

The following code can be compiled by:

var file1 two.IStream = new(File)var file2 one.ReadWriter = file1var file3 two.IStream = file2

Interface assignment does not require two interfaces to be equivalent. If the interface a method list is a subset of the interface B method list, then interface B can assign a value to interface a. For example, suppose we have a writer interface:

type Writer interface {    Write(buf []byte) (n int, err error)}

We can put the one above. Readwriter, both. An instance of the IStream interface assigns a value to the writer interface:

var file1 two.IStream = new(File)var file4 Writer = file1

But the reverse is not true:

var file1 Writer = new(File)var file5 two.IStream = file1 // 编译不能通过!

This code cannot be compiled through. The reason is obvious: File1 does not have a read method.

Interface Query

Is there a way to convert the above writer interface to the Two.istream interface? Yes. That's the interface query syntax we're going to discuss. The code is as follows:

var file1 Writer = ...if file5, ok := file1.(two.IStream); ok {    ...}

The meaning of this if statement is: whether the object instance pointed to by the File1 interface implements both. What about the IStream interface? If this is true, then ... The interface query is successful and is determined at run time. Unlike an interface assignment, the compiler only needs to pass a static type check to determine if the assignment is feasible.

People who have done development under windows have often been exposed to COM and know that COM also has an interface query (QueryInterface). Yes, the Go Language interface query is very similar to COM's interface query (QueryInterface), and it is possible to query other interfaces of an object implementation through an interface of an object (component). Of course, the Go Language interface query is much more elegant. In the go language, whether an object satisfies an interface or queries another interface through an interface is completely automatic.

Let the language built-in interface query, this is a very remarkable thing. The process of implementing QueryInterface in COM is cumbersome, but QueryInterface is the root of the COM system. The introduction of COM books to QueryInterface, often starting from a question like the following, it also applies in the Go language:

> Can you fly? IFly
> not.
> Can you swim? Iswim
> Will.
> Would you call? Ishout
> Will.
> ...

With the problem in-depth, you start to know nothing about the object (component) (in Go language is interface{}, in COM is IUnknown), to gradually have a deep understanding.

But can you finally fully understand the object? com says no, you can only approximate, but never fully understand a component. Go language says: Can you.

In the go language, you can ask the interface whether the object it points to is a type, as in the following example:

var file1 Writer = ...if file6, ok := file1.(*File); ok {    ...}

The meaning of this if statement is: Is the object instance pointed to by the File1 interface a *file type? If yes, then ...

You can think of whether the object that the query interface points to is a type, just a special case of the interface query. An interface is an abstraction of the public attributes of a set of types. So the difference between the query interface and the specific type of query is like the following two questions:

> Are you a doctor?
> is.
> Are you a XXX?
> is.

The first sentence for questioning is a group, is the query interface, and the second sentence has reached the specific individual, is the specific type of query.

In languages such as c++/java/c#, there are similar dynamic query capabilities, such as querying whether the type of an object inherits from a type (base-class query), or whether an interface (interface-derived query) is implemented. But their dynamic query is very different from Go's dynamic query.

> Are you a doctor?

For this problem, the base class query looks like this: "Is your father a doctor?" The interface derivation query looks like this: "Do you have a doctor's license?" In the go language, it is the first to determine what the conditions are to meet the doctor, such as the skills required, and then the condition of the torture, confirm whether the conditions are met, as long as you are the doctor, do not care whether you have a physician's license, or a small country license is not recognized by the Celestial Kingdom.

Type query

In the go language, you can also more directly query the type of object instances that the interface points to. For example:

var v1 interface{} = ...switch v := v1.(type) {    case int: // 现在v的类型是int    case string: // 现在v的类型是string    ...}

Just as the number of species in real life is countless, the types in the language are countless. So type queries are not often used. It looks more like a supplement and needs to be used in conjunction with an interface query. For example:

type Stringer interface {    String() string}func Println(args ...interface{}) {    for _, arg := range args {     switch v := v1.(type) {    case int: // 现在v的类型是int    case string: // 现在v的类型是string    default:        if v, ok := arg.(Stringer); ok { // 现在v的类型是Stringer            val := v.String()            ...        } else {            ...        }    }}

The println of the Go Language standard library is certainly much more complex than this example. Here we take the key parts for analysis. For built-in types, println uses the exhaustive method, which is converted to a string for each type to print. For a more general case, first determine whether the type implements the string () method, and if so, the string () method to be used for printing. Otherwise, println uses reflection (reflect) to traverse all member variables of the object for printing.

Yes, you can also make type queries with reflection (reflect), which can be found in detail in reflect. typeof method related documents. In the post-Wengau topic we will also explore the topic of "Reflection (reflect)".

Any type

Because any object instance in the go language satisfies the null interface interface{}, interface{} looks like an any type that can point to any object. As follows:

var v1 interface{} = 1      // 将int类型赋值给interface{}var v2 interface{} = "abc"    // 将string类型赋值给interface{}var v3 interface{} = &v2    // 将*interface{}类型赋值给interface{}var v4 interface{} = struct{ X int }{1}var v5 interface{} = &struct{ X int }{1}

When a function can accept arbitrary instances of an object, we declare it as interface{}. The most typical example is the function of the PRINTXXX series in the standard library FMT. For example:

func Printf(fmt string, args ...interface{})func Println(args ...interface{})...

We have already briefly analyzed the implementation of println, and have shown the use of interface{}. In summary, interface{} is similar to IUnknown in COM, we are just beginning to know nothing about it, but we can understand it through interface queries and type queries.

Summarize

We say that the Go Language Interface (interface) is more than just an interface. In other languages, interfaces exist only as contracts between components. From this aspect, the important breakthrough of the Go Language interface is that its interface is non-intrusive and eliminates the side effects of other language interfaces.

But the interface of the go language is not just a contractual function. It is an outline of the Go language type system. This is reflected in:

    • interface query: Through the interface you can query whether the object pointed to by the interface implements an additional interface.
    • type query: Through the interface you can query the specific type of object that the interface points to.
    • any type: interface{} in the go language can point to any object instance.
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.