Table of Contents
Understand the memory difference between []Struct and []Interface
Correctly implement the conversion from []Struct to []Interface
Notes: The difference between *[]Type and []*Type
Summarize
Home Backend Development Golang Go language interface slicing conversion: memory layout and type system analysis

Go language interface slicing conversion: memory layout and type system analysis

Sep 23, 2025 am 02:00 AM

Go language interface slicing conversion: memory layout and type system analysis

In Go language, slices of type []Struct cannot be assigned directly to slices of type []Interface, even if the structure Struct implements the corresponding interface. This is because there are fundamental differences in how the two are laid out in memory. Struct type slices store continuous structure values, while Interface type slices store continuous interface values ​​(each interface value consists of type information and data pointers/values). To achieve this transformation, a new interface slice must be constructed by explicitly traversing the slice and type conversion element by element. Furthermore, understanding the difference between *[]Type and []*Type is essential for the correct handling of Go slices and interfaces.

Understand the memory difference between []Struct and []Interface

The Go language type system is strongly typed, and slice types are no exception. []Person (a Person structure slice) and []Model (a Model interface slice) are two completely different types, and they are essentially different in memory.

  1. Structure slice ([]Person) : When defining a []Person slice, Go will allocate a continuous area in memory to store instances of Person structures. The size of each Person structure is fixed, determined by its internal fields. Therefore, []Person is essentially a continuous block of Person structure data.

  2. Interface slice ([]Model) : Unlike structures, interface values ​​in Go (such as Model type) are usually composed of two "words" in memory:

    • Type Word : Stores type information of the actual value (such as *Person or Person).
    • Data Word : Stores the actual value itself (if the value is small) or a pointer to the actual value (if the value is large or is of a reference type). When defining a []Model slice, Go allocates a continuous area in memory to store Model interface values. This means that each slice element is an interface value of a double word structure, rather than a direct Person structure.

Since []Person stores a series of Person structures, and []Model stores a series of interface values ​​of a double-word structure, their memory layout is completely incompatible. The Go compiler cannot directly interpret or convert a continuous block of Person structures into a continuous block of Model interface values ​​without performing additional operations. This conversion requires encapsulation of each element, which is an O(n) operation, and Go does not allow implicit conversions for performance and type safety.

Correctly implement the conversion from []Struct to []Interface

To convert a []Person slice to a []Model slice, you must explicitly traverse the original slice and encapsulate the structure instance into the interface value element by element, and then build a new interface slice.

Suppose we have the following Model interface and Person structure:

 package main

import "fmt"

// Model interface definition type Model interface {
    GetName() string
}

// Person structure implements Model interface type Person struct {
    Name string
    Age int
}

func (p Person) GetName() string {
    return p.Name
}

// newPerson Returns a pointer to a Person structure func newPerson(name string, age int) *Person {
    return &Person{Name: name, Age: age}
}

// newModel returns a Model interface value containing *Person
func newModel(c string) Model {
    switch c {
    case "person":
        return newPerson("Default Person", 30) // Model interface value will hold *Person
    }
    return nil
}

Now, if we have a []Person slice and want to convert it to a []Model:

 // Assume newPersons returns []Person
func newPersons() []Person {
    return []Person{
        {Name: "Alice", Age: 25},
        {Name: "Bob", Age: 30},
    }
}

// If you try to convert directly, an error will be reported: cannot use newPersons() (type []Person) as type []Model
/*
func getModelsDirectly() []Model {
    return newPersons()
}
*/

// Correct conversion method: explicitly traverse and convert func getModelsExplicitly() []Model {
    persons := newPersons()
    models := make([]Model, len(persons)) // Create a new []Model slice for i, p := range persons {
        // Assign each Person structure value to the Model interface.
        // Note: Here p is a copy of Person.
        // If the Model interface method requires a pointer receiver, or needs to modify the original structure,
        // You should use &persons[i] to get the address of the original structure.
        models[i] = p
    }
    return models
}

func main() {
    models := getModelsExplicitly()
    for _, m := range models {
        fmt.Printf("Model Name: %s\n", m.GetName())
    }

    // Example: newModel returns *Person, if you want the interface slice to also contain pointers fmt.Println("\nModels from points:")
    personsPtrs := []*Person{
        newPerson("Charlie", 35),
        newPerson("David", 40),
    }
    modelsFromPtrs := make([]Model, len(personsPtrs))
    for i, p := range personsPtrs {
        modelsFromPtrs[i] = p // p is already *Person, directly assign }
    for _, m := range modelsFromPtrs {
        fmt.Printf("Model Name (ptr): %s\n", m.GetName())
    }
}

In the getModelsExplicitly function above, we first create a new []Model slice with the same length as the persons slice. Then, we iterate through the persons slice, and for each Person instance p, assign it to models[i]. During this assignment process, the Person structure value is encapsulated into a Model interface value and stored in a new slice.

Notes: The difference between *[]Type and []*Type

In Go, the way slices and pointers are combined can sometimes be confusing, especially *[]Type and []*Type. Understanding their meaning is essential for writing clear and efficient code.

  1. * ` []Type (pointer to slice)**: This represents a pointer to the head of the slice. The slice itself is a structure containing a pointer, length, and capacity to the underlying array. []Type is a pointer to this structure. In Go, it is usually not necessary to use []Type, because when a slice is passed as a function parameter, it itself passes its header information by value, but its underlying array is shared. Modifying the content of the slice affects the original slice, but modifying the slice length or capacity (such as reallocation) does not. If you need to modify the slice header (such as reassigning slices), you can use *[]Type`.

     // Example: *[]Person (seldom used)
    var personsSlice []Person
    var ptrToPersonsSlice *[]Person = &personsSlice // ptrToPersonsSlice is a pointer to the personsSlice variable
  2. * `[] Type` (Slice to a Type Pointer)**: This represents a slice whose elements are a pointer to an instance of a specific type. This is a very common and useful pattern in Go, especially in the following scenarios:

    • Avoid copying large structures : If structures are large, storing their pointers in slices can avoid expensive copying during slice operations or function calls.
    • Implementing an interface : If the interface method is defined by the pointer receiver (for example, func (p *Person) GetName() string), then only *Person implements the interface. At this time, []*Person is a more suitable choice, because each element is already of *Person type and can be directly assigned to the Model interface.
    • Modify the underlying data : Through pointers in the slice, you can directly modify the underlying structure instance.
     // Example: []*Person
    personsPtrs := []*Person{
        newPerson("Grace", 28),
        newPerson("Heidi", 32),
    }
    // Convert []*Person to []Model
    modelsFromPtrs := make([]Model, len(personsPtrs))
    for i, p := range personsPtrs {
        modelsFromPtrs[i] = p // p is already *Person, and can be assigned directly to Model
    }

    If your Model interface is designed to accept *Person as the implementer (i.e. the interface method has a pointer receiver), the conversion from []*Person to []Model is more natural and avoids unnecessary copying.

Summarize

In Go language, []Struct cannot be converted directly to []Interface due to the fundamental difference in its underlying memory layout. To complete this transformation, a new interface slice must be constructed by explicitly traversing and encapsulating element by element. When designing slices and interfaces, you should weigh the use of value-type slices ([]Struct) or pointer-type slices ([]*Struct) based on actual needs, especially when it comes to large structures, interface implementation methods (value receivers or pointer receivers), and the need for underlying data modifications. Understanding these details is essential for writing robust and high-performance Go code.

The above is the detailed content of Go language interface slicing conversion: memory layout and type system analysis. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

ArtGPT

ArtGPT

AI image generator for creative art from text prompts.

Stock Market GPT

Stock Market GPT

AI powered investment research for smarter decisions

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to manage packages and imports in Go? How to manage packages and imports in Go? Sep 01, 2025 am 02:10 AM

UseGomodulesbyrunninggomodinittocreateago.modfile,whichmanagesdependenciesandversions.2.Organizecodeintopackageswhereeachdirectoryisapackagewithaconsistentpackagename,preferablymatchingthedirectoryname,andstructureimportsbasedonthemodulepath.3.Import

How to handle panics in a goroutine in Go How to handle panics in a goroutine in Go Aug 24, 2025 am 01:55 AM

Tohandlepanicsingoroutines,usedeferwithrecoverinsidethegoroutinetocatchandmanagethemlocally.2.Whenapanicisrecovered,logitmeaningfully—preferablywithastacktraceusingruntime/debug.PrintStack—fordebuggingandmonitoring.3.Onlyrecoverfrompanicswhenyoucanta

How to create a custom build tag in Go How to create a custom build tag in Go Aug 27, 2025 am 04:37 AM

CustombuildtagsinGoallowconditionalcompilationbasedonenvironment,architecture,orcustomscenariosbyusing//go:buildtagsatthetopoffiles,whicharethenenabledviagobuild-tags"tagname",supportinglogicaloperatorslike&&,||,and!forcomplexcondit

How to convert []int to []uint8 (byte array) in Go How to convert []int to []uint8 (byte array) in Go Sep 01, 2025 am 08:15 AM

This article explores how to convert []int slices to []uint8 (byte array) in Go. Given that the size of the int type in Go is platform-related (32-bit or 64-bit), the article details how to use the reflect package to dynamically obtain the int size, and combine the encoding/binary package to convert efficiently and safely in a large-endian manner, providing specific code examples and precautions to help developers cope with cross-platform data conversion challenges.

How to handle redirects in an HTTP client in Go How to handle redirects in an HTTP client in Go Aug 31, 2025 am 01:13 AM

Go's http.Client automatically tracks up to 10 redirects by default; 1. By default, redirects such as 301, 302, etc. will be automatically processed and the final response will be returned; 2. You can customize behavior by setting the CheckRedirect function, such as limiting the number of redirects, and return an error when len(via)>=3 to limit up to 2 redirects; 3. You can prevent redirects and get the original redirect response by returning http.ErrUseLastResponse, which is convenient for checking the Location header; 4. You can modify the request during the redirection process, such as deleting the Authorization header according to the target domain name to prevent sensitive information leakage; 5. You need to pay attention to looping

Go language concurrent programming: Understanding and using sync.WaitGroup Go language concurrent programming: Understanding and using sync.WaitGroup Aug 31, 2025 am 07:48 AM

sync.WaitGroup is an important primitive for concurrent synchronization in Go language. It allows the main goroutine to wait for a group of sub goroutines to be executed. Through the counter mechanism, WaitGroup can ensure that all concurrent tasks are completed and the program continues to be executed, effectively avoiding race conditions and resource leakage, and is a key tool for building robust concurrent applications.

How to embed static assets in a Golang binary How to embed static assets in a Golang binary Aug 30, 2025 am 04:50 AM

Using Go's embed package, you can embed static resources directly into binary files. Starting from Go1.16, by using the //go:embed directive before variables, a single file, multiple files or entire directories can be embedded, supporting string, []byte or embed.FS types. The embedded content is solidified into binary at compile time. The path needs to exist and is case sensitive. It is recommended to use embed instead of third-party tools such as go-bindata. This method is simple and efficient and has become a standard practice.

Start an external editor in the Go program and wait for it to complete Start an external editor in the Go program and wait for it to complete Sep 16, 2025 pm 12:21 PM

This article describes how to start an external editor (such as Vim or Nano) in a Go program and wait for the user to close the editor before the program continues to execute. By setting cmd.Stdin, cmd.Stdout, and cmd.Stderr, the editor can interact with the terminal to solve the problem of startup failure. At the same time, a complete code example is shown and precautions are provided to help developers implement this function smoothly.

See all articles