Structs
Creating
// Since it is not Uppercase, it is only available inside the package
type user struct {
name string
email string
}
Nesting structs
type system struct {
date string
user user
}
Struct tags
You can assign metadata to struct fields.
Some Go package functions make use of them.
For instance, the json
Go package uses metadata to define the key property names. Without the metadata the json keys would be Date: "", User: ""
, and with them date: "", user_data: ""
.
type system struct {
Date string `json:"date"`
User user `json:"user_data"`
}
Assiging values
When unassigned a value, a struct variable will be structname{}
.
For instance, the user
variable "null" value will be the empty struct user{}
.
var user user // Will by default hold the value "user{}"
var user user = user{} // Or you may explicitly set to an empty struct
Struct Literal or Composite Literal
user = user{
name: "Username",
email: "user@user"
}
Or you assign pass variable values.
userName := "Username"
userEmail := "user@user"
user = user{
name: userName,
email: userEmail
}
If the values are passed in the same order as they were declared in the structure you may omit the keys. (Otherwise values will be assigned to the wrong keys)
user = user{
"Username",
"user@user"
}
Unassigned struct properties will have their default "null" values.
Access property values
Use .
to access a struct property value.
fmt.Print(user.name)
Structs as parameters
Structs are good examples of when to use pointers to pass data by reference, in order to avoid memory duplication.
If passed without pointers, they will be passed by value.
// user if passed by value
func name(user user) {
user.name
}
name(user)
// user receives struct memory address
name(&user)
func name(user *user){
// This is technically the correct way
(*user).name
// But Go handles accessing the normal way
user.name
}
As stated above in the comments, Go handles as a shortcut, to access properties of a structure pointer the same way as a structure value. (With .
)
There is no need to access the pointer value, before accessing the property value, like (*user).name
.
Struct Methods
You can attach functions as struct properties, to give behavior to structures variables.
The function is not declared inside the structure, like it is in a JS
class.
Instead it is normally declared in the .go
file, along with the structure, but you provide a special parameter called Receiver
which states that the function belongs to the structure and allows the function to access the structure properties.
type user struct {
name string
age int
}
func (user user) showAge() {
fmt.Print(user.age)
}
func main() {
var u user = user{
"Username",
15
}
u.showAge()
}
Mutating struct values
The way done above can only read values from the struct.
To mutate and change the data you have to pass the Receiver
as a pointer.
Just like regular function parameters, the Receiver
parameter is also by default passed by value.
type user struct {
name string
age int
}
func (user *user) setAge(value int) {
user.age = value
}
func main() {
var u user = user{
"Username"
}
u.setAge(15)
}
constructors
These are convention functions to handle the creation of "new instances" of struct variables.
They are not Go features, but only a convention pattern.
By convention, constructors start with new
prefix in the function name.
type user struct {
name string
age int
}
func newUser(name string, age int) *user {
return &user{
name,
age
}
}
var user *user = newUser('Username', 15)
Also make sure to return references to the data, otherwise two copies will be created.
One inside the function.
One for the outside.
Isolating them in packages
In a struct, not only its name should be Uppercase, but also all the properties that should be "public".
When isolated, it is common that the constructor function will be named only New
.
package user
type User struct {
// Don't do it like this, check bellow
Name string
Age int
}
func New(name string, age int) *user {
return &user{
name,
age
}
}
package main
import "your-module/user"
var user *user.User = user.newUser("Username", 15)
Following object oriented principles
Since properties of a "class" should not be available to be used at will, struct properties should also no be accessible.
package user
type User struct {
name string
age int
}
func (user user) PrintAge() {
fmt.Print(user.age)
}
func New(name string, age int) (*user, error) {
if name == "" || age == 0 {
return nil, errors.New("invalid values for User")
}
return &user{
name,
age
}, nil
}
The constructor should be available, or even other types of design patterns, to preserve entity integrity.
This way you may even set validation on struct creation.
Struct embedding
Also known as inheritance
in other Object Oriented languages.
Define anonymously
package user
type User struct {
name string
age int
}
type Admin struct {
email string
password string
// Here "Admin" will inherit "User" anonymously, but privately
User
// To inherit anonymously and public
User: User
}
...
func NewAdmin() Admin {
return Admin{
email: "",
password: "",
User: User{
name: "Admin",
age: 45
}
}
}
admin := user.NewAdmin()
// Access to the "User" structure will show normaly
admin.PrintAge()
Define with a specific name
package user
type User struct {
name string
age int
}
type Admin struct {
email string
password string
// Here "Admin" will inherit "User" with by a specific "user" name
User User
}
...
func NewAdmin() Admin {
return Admin{
email: "",
password: "",
// Must use the specified name
User: User{
name: "Admin",
age: 45
}
}
}
admin := user.NewAdmin()
// Access to the "User" structure must "go through the "user" property
admin.User.PrintAge()
Last updated