SoFunction
Updated on 2025-03-05

Detailed explanation of how to initialize Struct using Go

introduction

The most basic concept of object-oriented programming language is classes (class),butGoThe language does not have a class concept, so it is usedGoWhen developing languages, we usually usestruct(structure)To simulate classes in object-oriented.

Classes are usually constructed by a constructor (constructors) to initialize the properties in the instance (object) of the class, butGoofstructThere is no mechanism like constructing methods, so how to initialize itstructWhat about the instance of type?

Let's introduce several creationsstructMethods of type variables.

Literal

Create and initialize astructThe easiest and most direct way to use variables isstructLiteral:

//app/
package school

type Student struct {
	ID    int
	Name  string
	Score int
	Grade string
}

//
package main
func main() {
	s := &Student{
		ID:    1,
		Name:  "Xiao Ming",
		Score: 90,
		Grade: "Class 2 of High School",
	}
}

But sometimes we just need a temporarystructFor type, anonymous can be usedstruct

func main() {

	s := struct {
		ID    int
		Name  string
		Score int
		Grade string
	}{
		ID: 1, 
        Name: "Xiao Ming",
        Score: 90,
        Grade: "Second Grade in High School",
	}
}

Use built-in new function

In addition to literality, useGoThe built-in new function can also create astructVariables, but this method requiresstructAssign initial values ​​to each field:

func main(){
  s := new(Student)
   = 1
   = "Xiao Ming"
   = 90
   = "Class 2 of High School"
}

Constructor

We've said it beforeGoLanguagestructThere is no constructor, but we can customize the function to initialize itstruct, the advantage of custom functions is:

  • The purpose of reuse can be achieved.
  • Can be packaged.
  • You can verify that the initialization value is within the allowed range.

Generally, our custom constructors areNewPrefix, for example:

package school

type student struct {
	ID    int
	Name  string
	Score int
	Grade string
}

func NewStudent(ID int, Name string,Score int Grade string) *Student {
    if ID < 0{
        panic("ID cannot be less than 0")
    }
    
    if Score < 0 || Score > 100{
        panic("Score must be between 0 and 100")
    }
    
    s := new(Student)
     = 1
     = "Xiao Ming"
     = 90
     = "Class 2 of High School"
    return s
}

package main 

import "app/school"

func main(){
    s := (1,"Xiao Ming",90,"Class 2 of High School")
}

In the above example, we customizedNewStudent()The function can be reused in other packages to initializestruct,WillStudentChange tostudent, so that other packages cannot be accessed directlystudentThe structure achieves the effect of packaging, andNewStudent()In the function, we can also verify whether the parameters are reasonable.

Of course, custom constructors must also beNewprefixed, such as standard libraryosIn the package, you can use it when initializing the file handle.Open()Create()andOpenFile()Wait for the function to initialize

//The file code of the os packagefunc Open(name string) (*File, error) {
	return OpenFile(name, O_RDONLY, 0)
}

func Create(name string) (*File, error) {
	return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
}

func OpenFile(name string, flag int, perm FileMode) (*File, error) {
	(name)
	f, err := openFileNolog(name, flag, perm)
	if err != nil {
		return nil, err
	}
	 = flag&O_APPEND != 0

	return f, nil
}

Constructors that support variadic parameters

In the above example, we can useNewStudent()Function creates astudentVariable of type, but the order and number of parameters of this constructor are fixed, if there are multiple places to callNewStudent()Function, when a new parameter is added to the function, all codes called to the function must be adjusted.

We can optimize our constructor again, using the number and order of its parameters that are variable:

package school

type student struct {
	ID    int
	Name  string
	Score int
	Grade string
}

type StudentOptionFunc func(*student)

func WithID(id int) StudentOptionFunc {
	return func(s *student) {
		 = id
	}
}

func WithName(name string) StudentOptionFunc {
	return func(s *student) {
		 = name
	}
}

func WithScore(score int) StudentOptionFunc {
	return func(s *student) {
		 = score
	}
}

func WithGrade(grade string) StudentOptionFunc {
	return func(s *student) {
		 = grade
	}
}

func NewStudent(opts ...StudentOptionFunc) *student {
	s := &student{}
	for _, opt := range opts {
		opt(s)
	}
	return s
}

In the example above, the constructorNewStudent()The parameters are indefinitely longStudentOptionFuncA function of type can be regarded as a slice containing multiple functions,NewStudent()The function traverses the slice internally and initializes its own fields through each function in the slice.

Next, in the call, we can call without being affected by the number and order of parameters.NewStudent()Function:

package main

import (
	"app/school"
	"fmt"
)

func main() {
	s1 := (
		("Xiao Ming"), 
        (90),
        (1),
        (""),
	)	
    
    s2 := (
		("Little Flower"), 
        (90),
	)	
}

Promise plan

The above demonstrates two custom constructors. One is to initialize the number and order of parameters completely fixed. This method is too rigid, while the other is to pass the order and number of parameters freely. This method is too free, because we can think of a compromise solution, that is, to combine the two methods:

func NewStudent(id int, Name string, opts ...StudentOptionFunc) *student {
	s := &student{ID: id, Name: Name}
	for _, opt := range opts {
		opt(s)
	}
	return s
}

summary

Several initializations introduced abovestructThere is no difference between good and bad in the way, choose the way you like to initialize itstructJust variables.

This is the end of this article about the detailed explanation of the method of Go initializing Struct. For more related content on Go initializing Struct, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!