How to determine whether the golang structure is empty
How to determine that golang structure is empty? It is to determine whether it has been initialized
The method is as follows:
You can use if objectA== (structname{}){ // your code } to make judgments.
The sample code is as follows:
package main import ( "fmt" "reflect" ) type A struct{ name string age int } func (a A) IsEmpty() bool { return (a, A{}) } func main() { var a A if a == (A{}) { // Can't go to brackets ("a == A{} empty") } if () { ("reflect deep is empty") } }
golang empty interface empty structure
Empty interface
- An empty interface is a special form of interface type. There is no method for an empty interface, so no empty interface is required for any type. From an implementation point of view, any value meets the needs of this interface. Therefore, the empty interface type can save any value, or the original value can be taken out from the empty interface.
- The empty interface type is similar to Object in C# or Java language, void* in C language, and std::any in C++. Before generics and templates appeared, empty interfaces were a very flexible way to save and use data abstractions and use them.
The internal implementation of the empty interface saves the object's type and pointer. The process of saving a data using an empty interface will be slightly slower than directly using variables of the corresponding type of data. Therefore, in development, you should use empty interfaces where you need them, rather than empty interfaces everywhere.
Variables of empty interface type can store variables of any type. Even the receiving pointer type uses interface{} instead of *interface{}.
Never use a pointer to point to an interface type, because it is already a pointer.
package main import "fmt" func main() { // Define an empty interface x var x interface{} s := "" x = s ("type:%T value:%v\n", x, x) i := 100 x = i ("type:%T value:%v\n", x, x) b := true x = b ("type:%T value:%v\n", x, x) }
Empty interface memory allocation
Will there be additional heap memory allocation in var i interface{} = a in Go 1.15?
var a int = 3 // Are there any additional memory allocations below?var i interface{} = a
Go 1.15 mentioned an interesting improvement in the runtime section: converting small integers to interface values no longer requires memory allocation. A small integer refers to a number between 0 and 255.
Application of empty interface
1. Empty interface as a parameter of a function
Using an empty interface implementation can receive any type of function parameters.
// Empty interface as function parameterfunc show(a interface{}) { ("type:%T value:%v\n", a, a) } //The number of parameters of the function and the type of each parameter are not fixed.func myfunc(args ...interface{}) { }
2. The empty interface is used as various types of values of map, array, and slice
func main() { // Empty interface as map value var studentInfo = make(map[string]interface{}) studentInfo["name"] = "Li Bai" //string studentInfo["age"] = 18 //int studentInfo["height"] = 1.82 //float studentInfo["married"] = false //bool (studentInfo) var a = new([3]interface{}) a[0] = "Hello,World" a[1] = 32 for _, b := range a { ("%v\t%[1]T\n", b) } }
3. Type Assertion
The value of an interface (referred to as an interface value) is composed of two parts: a specific type and a specific type of value. These two parts are called the dynamic type and dynamic value of the interface respectively.
func main() { var x interface{} x = "" v, ok := x.(string) if ok { (v) } else { ("Type assertion failed") } }
4. Type judgment
func justifyType(any interface{}) { switch v := any.(type) { case string: ("any is a string,value is: %v\n", v) case int: ("any is a int is: %v\n", v) case bool: ("any is a bool is: %v\n", v) case float32, float64: ("any is a float is: %v\n", v) default: ("unsupport type:%T is: %v\n", v, v) } } func main() { var x interface{} x = "" justifyType(x) x = 0.1 justifyType(x) }
Because empty interfaces can store the characteristics of any type of value, empty interfaces are widely used in the Go language.
Empty structure
We say that a structure that does not contain any fields is called an empty structure. An empty structure can be defined in the following ways:
type empty struct{}
Features
The address is the same
We define two non-empty structures and empty structure variables respectively, and then take the address to print them. We find that the addresses of the empty structure variables are the same:
// Define a non-empty structuretype User struct { name string } func main() { // The variable addresses of two non-empty structures are different var user1 User var user2 User ("%p \n", &user1) // 0xc000318670 ("%p \n", &user2) // 0xc000318680 // Define two empty structures with the same address var first struct{} var second struct{} ("%p \n", &first) // 0x1ca15f0 ("%p \n", &second) // 0x1ca15f0 }
We know that variable transfers in Go are all value transfers. The variable addresses before and after passing parameters should be different. Let’s try it again by passing parameters:
// Non-empty structuretype NonEmptyUser struct { name string } // Empty structuretype EmptyUser struct{} // Print the parameter address of non-empty structurefunc testNonEmptyUser(user NonEmptyUser) { ("%p \n", &user) } // Print empty structure parameter addressfunc testEmptyUser(user EmptyUser) { ("%p \n", &user) } func main() { // The variable addresses of two non-empty structures are different var user1 NonEmptyUser ("%p \n", &user1) // 0xc0001986c0 testNonEmptyUser(user1) // 0xc0001986d0 // The addresses of two empty structure variables are the same var user2 EmptyUser ("%p \n", &user2) // 0x1ca25f0 testEmptyUser(user2) // 0x1ca25f0 }
It was found that for non-empty structures, the addresses before and after the parameter transmission are different, but for empty structure variables, the addresses before and after are the same.
Memory occupancy size is 0
In Go, we can use : to calculate the number of bytes occupied by a variable, so let’s take a few examples:
type EmptyUser struct{} func main() { var i int var s string var m []string var u EmptyUser ((i)) // 8 ((s)) // 16 ((m)) // 24 ((u)) // 0 }
You can see that the memory space occupied by an empty structure is 0, and the space occupied by a combination of an empty structure is also 0:
// Combination of empty structurestype EmptyUser struct { name struct{} age struct{} } func main() { var u EmptyUser ((u)) // 0 }
Principle Exploration
Why are the addresses of empty structures the same and the size is 0? Let's take a look at the source code (go/src/runtime/):
// base address for all 0-byte allocations var zerobase uintptr // When creating a new object, call mallocgc to allocate memoryfunc newobject(typ *_type) { return mallocgc(, typ, true) } func mallocgc(size uintptr, typ *_type, needzero bool) { if gcphase == _GCmarktermination { throw("mallocgc called with gcphase == _GCmarktermination") } if size == 0 { return (&zerobase) } ...... }
From the source code, we can see that when creating a new object, we need to call () for memory allocation and further call the mallocgc method. In this method, if the size of the type is judged, the zerobase address is fixedly returned.
zerobase is a uintptr global variable that takes up 8 bytes. So what we can be sure is that in Go language, all memory allocations for size==0 use the same address &zerobase, so all empty structure addresses we see at the beginning are the same.
Use scenarios
If an empty structure does not contain any data, then its application scenario should not care about the value content and just treat it as a placeholder. In this scenario, since it does not occupy memory space, using an empty structure can not only save space, but also provide semantic support.
Set (Set)
Students who have used Java should have used the Set type. Set is a collection that holds no duplicate elements, but Go does not provide native Set type.
However, we know that the Map structure stores the key-value type, and the key does not allow duplication, so we can use Map to implement Set. The key stores the required data, and just give a fixed value to the value.
So what value is good for value? At this time, our empty structure can appear, without occupying space, and can also complete the placeholding operation, which is perfect. Let's see how to achieve it.
For example, when using map to represent a collection, only focus on the key, and value can use struct{} as the placeholder. If you use other types as placeholders, such as int, bool, not only is memory wasteful, but it is also prone to ambiguity.
// Define a Set collection that saves the string typetype Set map[string]struct{} // Add an elementfunc (s Set) Add(key string) { s[key] = struct{}{} //The second {} represents the assignment} // Remove an elementfunc (s Set) Remove(key string) { delete(s, key) } // Whether to include an elementfunc (s Set) Contains(key string) bool { _, ok := s[key] return ok } // Initializationfunc NewSet() Set { s := make(Set) return s } // Test usefunc main() { set := NewSet() ("hello") ("world") (("hello")) ("hello") (("hello")) } func min(a int, b uint) { var min = 0 if a < 0 { min = a } else { min = copy(make([]struct{}, a), make([]struct{}, b)) } ("The min of %d and %d is %d\n", a, b, min) }
Signal transmission in channel
An empty structure and channel are a classic combination. Sometimes we just need a signal to control the running logic of the program and don’t care about its content.
In the following example, we define two channels to receive signals completed by two tasks. When a signal completed by the task is received, the corresponding action will be triggered.
func doTask1(ch chan struct{}) { () ("do task1") ch <- struct{}{} } func doTask2(ch chan struct{}) { ( * 2) ("do task2") ch <- struct{}{} } func main() { ch1 := make(chan struct{}) ch2 := make(chan struct{}) go doTask1(ch1) go doTask2(ch2) for { select { case <-ch1: ("task1 done") case <-ch2: ("task2 done") case <-( * 5): ("after 5 seconds") return } } }
In this article, we have learned the following content:
- An empty structure is a special structure that does not contain any elements
- The size of the empty structure is 0
- The empty structures are all the same
- Since the empty structure does not occupy space, it is suitable for realizing the Set structure, transmitting signals in the channel, etc. from the perspective of saving memory.
Summarize
The above is personal experience. I hope you can give you a reference and I hope you can support me more.