Home >Backend Development >Golang >How to implement common functions of encapsulated models in golang?
In Golang, common functions of encapsulated models can be implemented by using structures and methods. A structure is a custom data type that can be used to encapsulate related data and methods. Methods are functions associated with a structure, and the members of the structure can be accessed and manipulated within the method. By defining functions as structures, we can associate functions with specific structures to implement common operations in encapsulated models. In Golang, we can use receivers to specify the structure to which the method belongs. The receiver can be a value type or a pointer type, choose the appropriate receiver type according to your needs. By defining the structure method, we can implement common operations in the encapsulated model, such as getting or setting field values, performing specific operations, etc. In this way, we can access and operate the encapsulated data by calling the structure's methods, achieving more flexible and reusable code.
I have 2 packages as models:
category:
package class import ( "encoding/json" "student_management/model/base" ) type classes struct { classes []class } type class struct { id int `json:"student_id"` name int `json:"name"` homeroomteacherid int `json:"homeroom_teacher_id"` } func readdata() (chan class, int) { var classes classes bytevalue := base.readjson("db/student_class.json") json.unmarshal(bytevalue, &classes) classchannel := make(chan class) go func () { for i := 0; i < len(classes.classes); i++ { classchannel <- classes.classes[i] } close(classchannel) }() return classchannel, len(classes.classes) }
teacher:
package teacher import ( "encoding/json" base "student_management/model/base" ) type teachers struct { teachers []teacher `json:"teachers"` } type teacher struct { base.persions homeroomteacher bool `json:"homeroom_teacher"` } func readdata() (chan teacher, int) { var teachers teachers bytevalue := base.readjson("db/teachers.json") json.unmarshal(bytevalue, &teachers) teacherchannel := make(chan teacher) go func () { for i := 0; i < len(teachers.teachers); i++ { teacherchannel <- teachers.teachers[i] } close(teacherchannel) }() return teacherchannel, len(teachers.teachers) }
So you can see that the readdata function is executed repeatedly. Now I can call data from the channel using class.readdata()
and teacher.readdata()
.
How to write a readdata() function for use by two packages?
I tried creating a base package that uses generics like this:
package base func ReadData[Models any, Model any](fileName string, m Models) (chan interface{}, int) { byteValue := ReadJSON(fileName) json.Unmarshal(byteValue, &m) channel := make(chan Model) go func () { for i := 0; i < len(m.Models); i++ { channel <- m.Models[i] } close(channel) }() return channel, len(models.Models) }
But cannot find m.models
, I mean teachers.teachers
or classes.classes
cannot be used
Please tell me what to do in this case
Use generics (introduced in go 1.18). Create a readdata()
function with parameter types representing the values to be decoded from json and passed on the channel.
Note: You should check for errors and report errors (including errors from base.readjson()
).
func readdata[t any](filename, fieldname string) (chan t, int, error) { var m map[string][]t bytevalue := base.readjson(filename) if err := json.unmarshal(bytevalue, &wrapper); err != nil { return nil, 0, err } values := m[fieldname] valueschannel := make(chan t) go func() { for _, v := range values { valueschannel <- v } close(valueschannel) }() return valueschannel, len(values), nil }
Call example:
ch, n, err := readdata[class.class]("db/student_class.json", "classes") // or ch, n, err := readdata[teacher.teacher]("db/teachers.json", "teachers")
Please note that returning the number of read values should be redundant. Since you closed the returned channel correctly, the caller can use for range
on the returned channel and the channel will correctly receive all values sent on it and then terminate.
Also note that since all values are ready (decoded) when returning to the channel, this concurrency is redundant and only reduces efficiency. You have a slice of decoded values, just return it and let the caller choose how it wants to handle it (concurrent or non-concurrent).
So your readdata()
should look like this:
func readdata[t any](filename, fieldname string) ([]t, error) { var m map[string][]t bytevalue := base.readjson(filename) if err := json.unmarshal(bytevalue, &wrapper); err != nil { return nil, err } return m[fieldname] }
Also note that if the input json object has only one field, there is no need to pass fieldname
, you can get the value from the decoded m
map like this:
func readdata[t any](filename string) ([]t, error) { var m map[string][]t bytevalue := base.readjson(filename) if err := json.unmarshal(bytevalue, &wrapper); err != nil { return nil, err } for _, v := range m { return v, nil } return nil, errors.new("empty json") }
Then calling it is simple:
classes, err := ReadData[class.Class]("db/student_class.json") // or teachers, err := ReadData[teacher.Teacher]("db/teachers.json")
The above is the detailed content of How to implement common functions of encapsulated models in golang?. For more information, please follow other related articles on the PHP Chinese website!