Sign In
Sign In

Introduction to Strings in Go

Introduction to Strings in Go
Hostman Team
Technical writer
Go
06.12.2024
Reading time: 11 min

A string in Go is a basic data type that represents a simple sequence of bytes but comes with special methods for working with them.

Golang provides the built-in strings package, which contains essential (and quite simple) functions for handling string data. These functions are similar to typical string functions in other programming languages like C or C++.

In the examples in this article, we also use the fmt package to format and print strings to the console.

Apart from defining strings, Go offers an extensive set of capabilities for performing various string manipulations.

Declaring Strings

It is worth mentioning that strings in Golang are somewhat different from those in Java, C++, or Python. A string in Go is a sequence of characters where each character can vary in size, which means it can be represented by one or more bytes in UTF-8 encoding.

Historically, when the C language was developed, a character in a computer was represented by a 7-bit ASCII code. Thus, a string was essentially a collection of multiple 7-bit ASCII characters.

However, as the use of computers grew globally, the 7-bit ASCII scheme became insufficient for supporting characters from different languages. This led to the development of various character encoding models like Unicode, UTF-8, UTF-16, UTF-32, etc.

Different programming languages adopted their own character encoding schemes. For example, Java originally used UTF-16. On the other hand, Go is built on UTF-8 encoding.

Thanks to UTF-8, Golang strings can contain universal text, representing a mix of any existing language in the world — without confusion or limitations. Additionally, strings in Go are immutable, meaning you cannot change their content after they are created.

Declaring Strings with Double Quotes

There are several common ways to declare (define) strings in Go:

// Explicit declaration using "var"
var variable1 = "some text"

// Explicit declaration using "var" with a type specified
var variable2 string = "peace"

// Shorter declaration
variable3 := "some text"

You can also declare a string without an explicit value. In this case, the string variable is initialized with a zero value, which is an empty string:

var variable4 string

When double quotes are used to create a string variable, Golang interprets special (escaped) characters, written with a backslash (\). For example, \n represents a new line:

import "fmt"

...

var some_variable = "first line\nsecond line\nthird line"

fmt.Println(some_variable) // Print the string to the console

// OUTPUT:
// first line
// second line
// third line

Declaring Strings with Backticks

To make the Go compiler ignore special characters and preserve the original formatting of strings, you can use backticks (`).

Here’s an example of declaring a Go string with explicit formatting:

import "fmt"

...

// Line breaks in the variable are specified explicitly without adding special characters
var some_variable = `first line
second line
third line`

fmt.Println(some_variable) // Print the string to the console

// OUTPUT:
// first line
// second line
// third line

Notice that the fmt package is used to output strings to the console.

In this example, Golang completely ignores escaped characters:

import "fmt"

...

var some_variable = `upper line \n lower line`

fmt.Println(some_variable) // Print the string to the console

// OUTPUT: upper line \n lower line

Modifying Strings in Go

The purpose of the special String type is to allow working with more than just a "raw" sequence of bytes; it provides dedicated methods for managing strings.

However, strictly speaking, strings are immutable in Go (unlike C and C++) — they cannot be changed. You can only access individual characters by their index:

import "fmt"

...

variable := "hello"
c := variable[0]

fmt.Printf("%c\n", c) // OUTPUT: h

Despite this, there are many ways to create new strings from existing ones.

Some functions for string manipulation require the strings package:

import "strings"

String Concatenation in Golang

The most basic string manipulation is concatenating multiple strings into one. This is done using the + operator:

import "fmt"

...

var variable1 = "hello"
var variable2 = "world"
var space = " "

var variable3 = variable1 + space + variable2

fmt.Println(variable3) // OUTPUT: hello world
fmt.Println(variable2 + ", " + variable1) // OUTPUT: world, hello

Note: You cannot add strings to other types, such as numbers:

fmt.Println("I am " + 24 + " years old") // ERROR

To make the above example work, you need to convert the number to a string using a type conversion function, such as strconv.Itoa:

import "fmt"
import "strconv"

...

age := 24

fmt.Println("I am " + strconv.Itoa(age) + " years old") // OUTPUT: I am 24 years old
fmt.Println("I am " + strconv.Itoa(24) + " years old") // OUTPUT: I am 24 years old

Trimming Strings

You can trim specific characters from the beginning and end of a string by specifying them as an argument:

import (
  "fmt"
  "strings"
)

...

result := strings.Trim("xxxhello worldxxx", "xxx")
fmt.Println(result) // OUTPUT: hello world

Splitting Strings

You can split a string into substrings by specifying a delimiter:

import (
  "fmt"
  "strings"
)

...

result := strings.Split("hello world", " ")
fmt.Println(result) // OUTPUT: [hello world

Joining Strings

You can join multiple Go strings stored in an array into a single string by explicitly specifying a delimiter:

import (
  "fmt"
  "strings"
)

...

result := strings.Join([]string{"hello", "world"}, " ") // an array of strings is provided as an argument
fmt.Println(result) // OUTPUT: hello world

However, using a join function or the + operator for string concatenation is not always efficient. Each such operation creates a new string, which can reduce performance.

To address this, Go provides an optimized tool for constructing strings from components while following specific rules — the Builder:

import (
  "fmt"
  "strings"
)

...

builded := &strings.Builder{}

builded.WriteString("very")
builded.WriteString(" ")
builded.WriteString("long")
builded.WriteString(" ")
builded.WriteString("line")

fmt.Println(builded.String()) // OUTPUT: very long line

For more details, refer to the official Golang documentation on the Builder type. Despite its powerful optimization capabilities, it is straightforward to use, as it doesn’t have a large number of methods.

Splitting Strings

You can split a string into parts by specifying a delimiter as an argument:

import (
  "fmt"
  "strings"
)

...

result := strings.Split("h-e-l-l-o", "-")

fmt.Println(result) // OUTPUT: [h e l l o]

Replacing Substrings

Go provides several ways to replace a substring with another:

import (
  "fmt"
  "strings"
)

...

result := strings.Replace("hello", "l", "|", 1) // replace the first occurrence
fmt.Println(result) // OUTPUT: he|lo

result = strings.Replace("hello", "l", "|", -1) // replace all occurrences
fmt.Println(result) // OUTPUT: he||o

Changing String Case

Go also provides methods to switch the case of a string — converting to uppercase or lowercase:

import (
  "fmt"
  "strings"
)

...

fmt.Println(strings.ToUpper("hello")) // OUTPUT: HELLO
fmt.Println(strings.ToLower("HELLO")) // OUTPUT: hello

Creating a String from a Sequence of Bytes

You can also convert a sequence of bytes into a full-fledged string and then work with it:

import "fmt"

...

// byte sequence
any_bytes := []byte{0x47, 0x65, 0x65, 0x6b, 0x73}

// create a string
any_string := string(any_bytes)

fmt.Println(any_string) // OUTPUT: Geeks

Comparing Strings

Searching for a Substring

One way to check if a substring is present in a string is by using the strings.Contains function:

import (
  "fmt"
  "strings"
)

...

result := strings.Contains("world", "rl")
fmt.Println(result) // OUTPUT: true

result = strings.Contains("world", "rrl")
fmt.Println(result) // OUTPUT: false

Classic Comparison Operators

You can also use standard comparison operators to check for matches. These operators compare strings character by character in lexicographical order and consider the length of the strings:

import "fmt"

...

fmt.Println("hello" == "hello")       // OUTPUT: true
fmt.Println("hello" == "hello world") // OUTPUT: false
fmt.Println("hello" > "hell")         // OUTPUT: true
fmt.Println("hello" > "lo")           // OUTPUT: false

Checking for Prefixes and Suffixes

In addition to searching for substrings, you can check if a string contains a specific prefix or suffix using strings.HasPrefix and strings.HasSuffix:

import (
  "fmt"
  "strings"
)

...

result := strings.HasPrefix("hello", "he")
fmt.Println(result) // OUTPUT: true

result = strings.HasSuffix("hello", "lo")
fmt.Println(result) // OUTPUT: true

result = strings.HasPrefix("hello", "el")
fmt.Println(result) // OUTPUT: false

Finding the Index of a Substring

You can obtain the index of the first occurrence of a specified substring using the strings.Index function:

import (
  "fmt"
  "strings"
)

...

result := strings.Index("hello", "el")
fmt.Println(result) // OUTPUT: 1

result = strings.Index("hello", "le")
fmt.Println(result) // OUTPUT: -1

If the substring is not found, the function returns -1.

String Length

To determine the length of a string in Golang, you can use the built-in len function:

import "fmt"

...

length := len("hello")

fmt.Println(length) // OUTPUT: 5

Since Go uses UTF-8 encoding, the length of a string corresponds to the number of bytes, not the number of characters, as some characters may occupy 2 or more bytes.

Iterating Over a String

In some cases, such as comparing strings or processing their content, you may need to iterate through a string's characters manually.  This can be achieved using a for loop with a range clause:

import "fmt"

...

for symbol_index, symbol_value := range "Hello For All Worlds" {
  fmt.Printf("Value: %c; Index: %d\n", symbol_value, symbol_index)
  // additional actions can be performed here
}

This loop retrieves both the index and the value of each character in the string, making it easy to process each symbol individually.

String Output and Formatting

Formatting with Basic Types

The fmt package in Go offers powerful tools for formatting strings during their output. Similar to other programming languages, Golang uses templates and annotation verbs for formatting.

Here are some examples:

import "fmt"

...

// Formatting a string variable using %s
any_string := "hello"
result := fmt.Sprintf("%s world", any_string)

fmt.Println(result) // OUTPUT: hello world

// Formatting a number variable using %d
any_number := 13
result = fmt.Sprintf("there are %d worlds!", any_number)

fmt.Println(result) // OUTPUT: there are 13 worlds!

// Formatting a boolean variable using %t
any_boolean := true
result = fmt.Sprintf("this is the %t world!", any_boolean)

fmt.Println(result) // OUTPUT: this is the true world!

The Sprintf function formats and returns the string, which can then be printed to the console using Println.

Using Multiple Variables in Formatting

You can use more complex templates to include multiple variables in the same format string:

import "fmt"

...

// Formatting two strings in one template
first_string := "hello"
second_string := "world"
result := fmt.Sprintf("%s %s", first_string, second_string)

fmt.Println(result) // OUTPUT: hello world

// Formatting three numbers in one template
first_number := 10
second_number := 20
third_number := 30
result = fmt.Sprintf("%d and %d and %d", first_number, second_number, third_number)

fmt.Println(result) // OUTPUT: 10 and 20 and 30

// Formatting two boolean values in one template
first_boolean := true
second_boolean := false
result = fmt.Sprintf("if it is not %t therefore it means it is %t", first_boolean, second_boolean)

fmt.Println(result) // OUTPUT: if it is not true therefore it means it is false

Mixing Different Variable Types

You can combine variables of different types within a single formatted string:

import "fmt"

...

first_string := "hello"
second_number := 13
third_boolean := true

result := fmt.Sprintf("%s to all %d %t worlds", first_string, second_number, third_boolean)

fmt.Println(result) // OUTPUT: hello to all 13 true worlds

Formatting with Binary Data

Go allows for special formatting of numbers into binary representation using %b:

import "fmt"

...

first_number := 13
second_number := 25
result := fmt.Sprintf("%b and %b", first_number, second_number)

fmt.Println(result) // OUTPUT: 1101 and 11001

Conclusion

Go provides a small yet sufficient toolkit for string manipulation, covering most of a developer's needs.

One important concept to understand when working with Golang strings is that what we conventionally call "individual elements of a string" (characters) are actually sequences of UTF-8 bytes. This means that when working with strings, we are manipulating byte values.

As a result, any attempt (which is prohibited in Go) to modify a two-byte character into a single byte would result in an error.

Each time we "modify" a string, what we are actually doing is recreating it with updated values.

Similarly, when we query the length of a string, we are retrieving the number of bytes used, not the number of characters.

Nevertheless, Go's standard libraries are rich with functions for "manipulating" strings. This introductory article has demonstrated basic yet commonly used methods for interacting with strings in Golang.

Keep in mind that in most cases, advanced string usage requires importing the specialized strings package and leveraging the fmt package to format strings for console output.

For a complete and detailed reference of all available methods in the strings package, you can consult the official Go documentation. In addition,  you can deploy Go applications (such as Beego and Gin) on our app platform.

Go
06.12.2024
Reading time: 11 min

Similar

Microservices

Database Connection in Python, Go, and JavaScript

Databases are an essential part of almost any project today. Database interactions are especially familiar to system and database administrators, DevOps/SRE professionals, and software developers. While administrators typically deploy one or multiple database instances and configure the necessary connection parameters for applications, developers need to connect directly to the database within their code. This article explores how to connect to databases using different programming languages. Prerequisites We will provide examples for connecting to MySQL, PostgreSQL, Redis, MongoDB, and ClickHouse databases using Python, Go, and JavaScript. To follow this guide, you will need: A database deployed on a server or in the cloud. Installed environments for Python, Go, and JavaScript, depending on your application programming language. Additionally for Python: pip installed. Additionally for JavaScript: Node.js and npm installed. Database Connection in Python MySQL and Python For connecting to MySQL databases, we can use a Python driver called MySQL Connector. Install the driver using pip: pip install mysql-connector-python Initialize a new connection: Import the mysql.connector library and the Error class to handle specific connection errors. Create a function named create_connection, passing the database address (host), user name (user), and user password (password). To establish the connection, define a class called create_connection that receives the variable names containing the database connection details. import mysql.connector from mysql.connector import Error def create_connection(host_name, user_name, user_password): connection = None try: connection = mysql.connector.connect( host="91.206.179.29", user="gen_user", password="m-EE6Wm}z@wCKe" ) print("Successfully connected to MySQL Server!") except Error as e: print(f"The error '{e}' occurred") return connection def execute_query(connection, query): cursor = connection.cursor() try: cursor.execute(query) connection.commit() print("Query executed successfully") except Error as e: print(f"The error '{e}' occurred") connection = create_connection("91.206.179.29", "gen_user", "m-EE6Wm}z@wCKe") Run the script. If everything works correctly, you will see the "Successfully connected to MySQL Server!" message. If any errors occur, the console will display error code and description. Create a new table: Connect to the database using the connection.database class, specifying the name of the database. Note that the database should already exist. To create a table, initialize a variable create_table_query containing the SQL CREATE TABLE query. For data insertion, initialize another variable insert_data_query with the SQL INSERT INTO query. To execute each query, use the execute_query class, which takes the database connection string and the variable containing the SQL query. connection.database = 'test_db' create_table_query = """ CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, age INT NOT NULL ) """ execute_query(connection, create_table_query) insert_data_query = """ INSERT INTO users (name, age) VALUES ('Alice', 30), ('Bob', 25) """ execute_query(connection, insert_data_query) if connection.is_connected(): connection.close() print("Connection closed") Run the script. PostgreSQL and Python Python offers several plugins for connecting to PostgreSQL, but the most popular one is psycopg2, which we will use here. Psycopg2 is one of the most frequently used Python plugins for PostgreSQL connections. One of its key advantages is its support for multithreading which allows you to maintain the database connection across multiple threads. Install psycopg2 using pip (if not already installed): pip install psycopg2-binary Connect to PostgreSQL. Import the Python psycopg2 package and create a function create_new_conn, using the try block. Establish the connection with the psycopg2.connect function, which requires the database name, user name, password, and database address as input. To initialize the connection, use the create_new_conn() function. Here’s the full code example for connecting to a database: import psycopg2 from psycopg2 import OperationalError def create_new_conn(): conn_to_postgres = None while not conn_to_postgres: try: conn_to_postgres = psycopg2.connect( default_db="default_db", default_user="gen_user", password_for_default_user="PasswordForDefautUser9893#", db_address="91.206.179.128" ) print("The connection to PostgreSQL has been successfully established!") except OperationalError as e: print(e) return conn_to_postgres conn_to_postgres = create_new_conn() Run the script: python3 connect_to_postgres.py If successful, you will see the "The connection to PostgreSQL has been successfully established!" message. . Next, create a table named books, which will have three columns. Use the cursor class for SQL expressions, such as creating database objects. If the query involves adding or modifying data, you must call the conn_to_postgres.commit() function afterward to apply the changes. import psycopg2 from psycopg2 import OperationalError def create_new_conn(): conn_to_postgres = None while not conn_to_postgres: try: conn_to_postgres = psycopg2.connect( default_db="default_db", default_user="gen_user", password_for_default_user="PasswordForDefautUser9893#", db_address="91.206.179.128" ) except OperationalError as e: print(e) return conn_to_postgres conn_to_postgres = create_new_conn() cursor = conn_to_postgres.cursor() cursor.execute(""" CREATE TABLE books ( book_id INT PRIMARY KEY NOT NULL, book_name VARCHAR(255) NOT NULL, book_author VARCHAR(255) NOT NULL ) """) conn_to_postgres.commit() print("Table Created successfully") Run the script: python3 create_table.py Now, let’s run INSERT INTO to add a new line: cursor.execute(""" INSERT INTO books (book_id,book_name,book_author) VALUES (1, 'Long Walk to Freedom', 'Nelson_Mandela') """) The full code is below: import psycopg2 from psycopg2 import OperationalError def create_new_conn(): conn_to_postgres = None while not conn_to_postgres: try: conn_to_postgres = psycopg2.connect( default_db="default_db", default_user="gen_user", password_for_default_user="PasswordForDefautUser9893#", db_address="91.206.179.128" ) except OperationalError as e: print(e) return conn_to_postgres conn_to_postgres = create_new_conn() cursor = conn_to_postgres.cursor() cursor.execute(""" INSERT INTO books (book_id,book_name,book_author) VALUES (1, 'Long Walk to Freedom', 'Nelson_Mandela') """) conn_to_postgres.commit() conn_to_postgres.close() print("Data inserted successfully") Run the script: python3 insert-data.py Redis and Python Redis belongs to the class of NoSQL databases, where data is stored in memory rather than on hard drives. It uses a key-value format for data storage. Redis has a wide range of applications, from data storage and caching to serving as a message broker. We will use the redis-py (or simply redis) library for connecting to Redis. Install the Redis library using pip: pip install redis Connecting to a Redis instance: Use a try block structure for connection, specifying the function redis.StrictRedis where you provide the Redis address, port, and user password. import redis try: connect_to_redis_server = redis.StrictRedis( redis_db_host=91.206.179.128, redis_db_port=6379, redis_user_password='PasswordForRedis6379') print connect_to_redis_server connect_to_redis_server.ping() print 'Successfully connected to Redis Server!' except Exception as ex: print 'Error:', ex exit('Failed to connect to Redis server.') Run the script: python3 connect_to_redis.py If successful, you will see a message like "Successfully connected to Redis Server!". Unlike relational databases, Redis stores data in a key-value format. The key uniquely identifies the corresponding value. Use the set method to create a new record. The example below creates a record with the key City and the value Berlin: print('Create new record:', connect_to_redis_server.set("City", "Berlin")) Use the get method to retrieve the value associated with a key: print('Print record using record key:', connect_to_redis_server.get("City")) Use the delete method to remove a record by its key: print('Delete record with key:', connect_to_redis_server.delete("City")) The complete code fragment is below. import redis try: connect_to_redis_server = redis.StrictRedis( redis_db_host=91.206.179.128, redis_db_port=6379, redis_user_password='PasswordForRedis6379') print ('New record created:', connect_to_redis_server.set("City", "Berlin")) print ('Print created record using record key', connect_to_redis_server.get("City")) print ('Delete created record with key :', connect_to_redis_server.delete("City")) except Exception as ex: print ('Error:', ex) MongoDB and Python MongoDB is another widely used NoSQL database that belongs to the document-oriented category. Data is organized as JSON-like documents. To connect to a MongoDB database with Python, the recommended library is PyMongo, which provides a synchronous API. Install the PyMongo plugin: pip3 install pymongo Connect to MongoDB server using the following Python code. Import the pymongo module and use the MongoClient class to specify the database server address. To establish a connection to the MongoDB server, use a try block for error handling: import pymongo connect_to_mongo = pymongo.MongoClient("mongodb://91.206.179.29:27017/") first_db = connect_to_mongo["mongo-db1"] try: first_db.command("serverStatus") except Exception as e: print(e) else: print("Successfully connected to MongoDB Server!") connect_to_mongo.close() Run: python3 connect_mongodb.py If the connection is successfully established, the script will return the message: "Successfully connected to MongoDB Server!" Add data to MongoDB. To add data, you need to create a dictionary. Let's create a dictionary named record1, containing three keys: record1 = { "name": "Alex", "age": 25, "location": "London" } To insert the dictionary data, use the insert_one method in MongoDB. insertrecord = collection1.insert_one(record1) import pymongo connect_to_mongo = pymongo.MongoClient("mongodb://91.206.179.29:27017/") db1 = connect_to_mongo["newdb"] collection1 = db1["userdata"] record1 = { "name": "Alex", "age": 25, "location": "London" } insertrecord = collection1.insert_one(record1) print(insertrecord) Run the script: python3 connect_mongodb.py ClickHouse and Python ClickHouse is a columnar NoSQL database where data is stored in columns rather than rows. It is widely used for handling analytical queries. Install the ClickHouse driver for Python. There is a dedicated plugin for ClickHouse called clickhouse-driver. Install the driver using the pip package manager: pip install clickhouse-driver Connect to ClickHouse. To initialize a connection with ClickHouse, you need to import the Client class from the clickhouse_driver library. To execute SQL queries, use the client.execute function. You also need to specify the engine. For more details on supported engines in ClickHouse, you can refer to the official documentation. We'll use the default engine, MergeTree. Next, create a new table called users and insert two columns with data. To list the data to be added to the table, use the tuple data type. After executing the necessary queries, make sure to close the connection to the database using the client.disconnect() method. The final code will look like this: from clickhouse_driver import Client client = Client(host=91.206.179.128', user='root', password='P@$$w0rd123', port=9000) client.execute(''' CREATE TABLE IF NOT EXISTS Users ( id UInt32, name String, ) ENGINE = MergeTree() ORDER BY id ''') data = [ (1, 'Alice'), (2, 'Mary') ] client.execute('INSERT INTO Users (id, name) VALUES', data) result = client.execute('SELECT * FROM Users') for row in result: print(row) client.disconnect() Database Connection in Go Go is one of the youngest programming languages, developed in 2009 by Google.  It is widely used in developing microservice architectures and network utilities. For example, services like Docker and Kubernetes are written in Go. Go supports integrating all popular databases, including PostgreSQL, Redis, MongoDB, MySQL, ClickHouse, etc. MySQL and Go For working with the MySQL databases in Go, use the go-sql-driver/mysql driver. Create a new directory for storing project files and navigate into it: mkdir mysql-connect && cd mysql-connect Create a go.mod file to store the dependencies: go mod init golang-connect-mysql Download the MySQL driver using the go get command: go get -u github.com/go-sql-driver/mysql Create a new file named main.go. Specify the database connection details in the dsn variable: package main import ( "database/sql" "fmt" "log" _ "github.com/go-sql-driver/mysql" ) func main() { dsn := "root:password@tcp(localhost:3306)/testdb" db, err := sql.Open("mysql", dsn) if err != nil { log.Fatal(err) } defer db.Close() if err := db.Ping(); err != nil { log.Fatal(err) } fmt.Println("Successfully connected to the database!") query := "INSERT INTO users (name, age) VALUES (?, ?)" result, err := db.Exec(query, "Alex", 25) if err != nil { log.Fatal(err) } lastInsertID, err := result.LastInsertId() if err != nil { log.Fatal(err) } fmt.Printf("Inserted data with ID: %d\n", lastInsertID) } PostgreSQL and Go To connect to PostgreSQL, use the pq driver. Before installing the driver, let's prepare our environment. Create a new directory for storing the project files and navigate into it: mkdir postgres-connect && cd postgres-connect Since we will be working with dependencies, we need to create a go.mod file to store them: go mod init golang-connect-postgres Download the pq driver using the go get command: go get github.com/lib/pq Create a new file named main.go. In addition to importing the pq library, it is necessary to add the database/sql library as Go does not come with official database drivers by default. The database/sql library consists of general, independent interfaces for working with databases. It is also important to note the underscore (empty identifier) when importing the pq module: _ "github.com/lib/pq" The empty identifier is used to avoid the "unused import" error, as in this case, we only need the driver to be registered in database/sql. The fmt package is required to output data to the standard output stream, for example, to the console. To open a connection to the database, the sql.Open function is used, which takes the connection string (connStr) and the driver name (postgres). The connection string specifies the username, database name, password, and host address: package main import ( "database/sql" "fmt" "log" _ "github.com/lib/pq" ) func main() { connStr := "user=golang dbname=db_for_golang password=Golanguserfordb0206$ host=47.45.249.146 sslmode=disable" db, err := sql.Open("postgres", connStr) if err != nil { log.Fatal(err) } defer db.Close() err = db.Ping() if err != nil { log.Fatal(err) } fmt.Println("Successfully connected to PostgreSQL!") } Compile and run: go run main.go If everything works correctly, the terminal will display the message Successfully connected to PostgreSQL! Now, let's look at an example of how to insert data into a table.  First, we need to create a table in the database. When using Hostman cloud databases, you can copy the PostgreSQL connection string displayed in the "Connections" section of the Hostman web interface. Make sure that the postgresql-client utility is installed on your device beforehand. Enter the psql shell and connect to the previously created database: \c db_for_golang Create a table named Cities with three fields — city_id, city_name, and city_population: CREATE TABLE Cities ( city_id INT PRIMARY KEY, city_name VARCHAR(45) NOT NULL, city_population INT NOT NULL); Grant full privileges to the created table for the user: GRANT ALL PRIVILEGES ON TABLE cities TO golang; The function db.Prepare is used to prepare data. It specifies the query for insertion in advance. To insert data, use the function stmt.Exec. In Go, it's common to use plain SQL without using the ORM (Object-Relational Mapping) approach. stmt, err := db.Prepare("INSERT INTO Cities(city_id, city_name, city_population) VALUES($1, $2, $3)") if err != nil { log.Fatal(err) } defer stmt.Close() _, err = stmt.Exec(1, "Toronto", 279435) if err != nil { log.Fatal(err) } fmt.Println("Data inserted successfully!") } If all works correctly, you will see: Data inserted successfully! Redis and Go To connect to Redis, you need to use the go-redis driver. Сreate a new directory: mkdir connect-to-redis && cd connect-to-redis Prepare the dependency file: go mod init golang-connect-redis And optimize them: go mod tidy Download the go-redis module: go get github.com/go-redis/redis/v8 To connect to Redis, use the redis.Options function to specify the address and port of the Redis server. Since Redis does not use authentication by default, you can leave the Password field empty and use the default database (database 0): package main import ( "context" "fmt" "log" "github.com/go-redis/redis/v8" ) func main() { rdb := redis.NewClient(&redis.Options{ Addr: "91.206.179.128:6379", Password: "", DB: 0, }) ctx := context.Background() _, err := rdb.Ping(ctx).Result() if err != nil { log.Fatalf("Couldn't connect to Redis: %v", err) } fmt.Println("Successfully connected to Redis!") } You should see the message «Successfully connected to Redis!» MongoDB and Go To work with MongoDB, we'll use the mongo driver. Create a new directory to store the project structure: mkdir connect-to-mongodb && cd connect-to-mongodb Initialize the dependency file: go mod init golang-connect-mongodb Download the mongo library: go get go.mongodb.org/mongo-driver/mongo Connect to MongoDB using the options.Client().ApplyURI method. It takes a connection string such as mongodb://91.206.179.29:27017, where 91.206.179.29 is the MongoDB server address and 27017 is the port for connecting to MongoDB. The options.Client().ApplyURI string is used only for specifying connection data. To check the connection status, you can use another function, client.Ping, which shows the success or failure of the connection: package main import ( "context" "fmt" "log" "time" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) func main() { clientOptions := options.Client().ApplyURI("mongodb://91.206.179.29:27017") client, err := mongo.Connect(context.TODO(), clientOptions) if err != nil { log.Fatalf("Couldn't connect to MongoDB server: %v", err) } fmt.Println("successfully connected to MongoDB!") ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() err = client.Ping(ctx, nil) if err != nil { log.Fatalf("Could not ping MongoDB server: %v", err) } fmt.Println("Ping MongoDB server successfully!") } You should see the message: successfully connected to MongoDB!Ping MongoDB server successfully MongoDB uses collections to store data. You can create collections using the .Collection function.  Below, we will create a database called first-database and a collection called first-collection. The collection will have a new document, containing three keys: user-name, user-age, and user-email. collection := client.Database("first-database").Collection("first-collection") document := map[string]interface{}{ "user-name": "Alice", "user-age": 25, "user-email": "alice@corporate.com", } insertResult, err := collection.InsertOne(ctx, document) if err != nil { log.Fatalf("Couldn't insert new document: %v", err) } fmt.Printf("Inserted new document with ID: %v\n", insertResult.InsertedID) if err := client.Disconnect(ctx); err != nil { log.Fatalf("Could not disconnect from MongoDB: %v", err) } fmt.Println("Disconnected from MongoDB!") } If successful, you will see the Inserted new document message with the document ID.  ClickHouse and Go To work with ClickHouse, use the clickhouse-go driver. Create a new directory to store the project files and navigate to it: clickhouse-connect && cd clickhouse-connect Create a go.mod file to store the dependencies: go mod init golang-connect-clickhouse Download the Clickhouse driver using the command: go get github.com/ClickHouse/clickhouse-go/v2 Create a new file named main.go, where you will specify the connection data to ClickHouse. package main import ( "database/sql" "log" "github.com/ClickHouse/clickhouse-go/v2" ) func main() { dsn := "tcp://localhost:9000?username=user1&password=PasswordForuser175465&database=new_db" db, err := sql.Open("clickhouse", dsn) if err != nil { log.Fatal(err) } defer db.Close() if err := db.Ping(); err != nil { log.Fatal(err) } log.Println("Connected to ClickHouse!") } Database Connection in JavaScript In JavaScript, all connections to external services are made using the Node.js platform. Make sure that you have Node.js and the npm package manager installed on your device. MySQL and JavaScript To work with MySQL, use the mysql2 driver. Create a directory where we will store the project files: mkdir js-mysql-connect && cd js-mysql-connect Initialize the project: npm init -y Install the mysql2 library: npm install mysql2 Use the following code to connect to MySQL: const mysql = require('mysql2'); const connection_to_mysql = mysql.createConnection({ host: 'localhost', user: 'root', password: 'PasswordForRoot74463', database: db1, }); connection_to_mysql.connect((err) => { if (err) { console.error('Error connecting to MySQL:', err.message); return; } console.log('Successfully connected to MySQL Server!'); connection_to_mysql.end((endErr) => { if (endErr) { console.error('Error closing the connection_to_mysql:', endErr.message); } else { console.log('Connection closed.'); } }); }); PostgreSQL and JavaScript Connecting to PostgreSQL is done using the pg library. Create a directory where we will store the project files: mkdir js-postgres-connect && cd js-postgres-connect Initialize the project: npm init -y Install the pg library: npm install pg To connect to PostgreSQL, first import the pg library. Then, create a constant where you specify variables for the database address, username, password, database name, and port. Use the new pg.Client class to pass the connection data. We will create a table called cities and add two records into it. To do this, we will use the queryDatabase function, which contains the SQL queries. const pg = require('pg'); const config = { postgresql_server_host: '91.206.179.29', postgresql_user: 'gen_user', postgresql_user_password: 'PasswordForGenUser56467$', postgresql_database_name: 'default_db', postgresql_database_port: 5432, }; const client = new pg.Client(config); client.connect(err => { if (err) throw err; else { queryDatabase(); } }); function queryDatabase() { const query = ` DROP TABLE IF EXISTS cities; CREATE TABLE cities (id serial PRIMARY KEY, name VARCHAR(80), population INTEGER); INSERT INTO cities (name, population) VALUES ('Berlin', 3645000); INSERT INTO cities (name, population) VALUES ('Paris', 2161000); `; client .query(query) .then(() => { console.log('Table created successfully!'); client.end(console.log('Closed client connection')); }) .catch(err => console.log(err)) .then(() => { console.log('Finished execution, exiting now'); process.exit(); }); } Use this command to run the code: node connect-to-postgres.js Redis and JavaScript To work with Redis, use the ioredis library. Create a directory to store the project files: mkdir js-redis-connect && cd js-redis-connect Initialize the project: npm init -y Install the ioredis library: npm install ioredis To connect to Redis, import the ioredis library. Then create a constant named redis and specify the Redis server address. Inserting data, i.e., creating key-value objects, is done using an asynchronous function named setData, which takes two values — key and value, corresponding to the data format of the Redis system. const Redis = require('ioredis'); const redis = new Redis({ host: '91.206.179.29', port: 6379, password: 'UY+p8e?Kxmqqfa', }); async function setData(key, value) { try { await redis.set(key, value); console.log('Data successfully set'); } catch (error) { console.error('Error setting data:', error); } } async function getData(key) { try { const value = await redis.get(key); console.log('Data retrieved'); return value; } catch (error) { console.error('Error getting data:', error); } } (async () => { await redis.select(1); await setData('user', 'alex'); await getData('user'); redis.disconnect(); })(); Run: node connect-to-redis.js MongoDB and JavaScript To work with MongoDB, use the mongodb driver. Create a directory for storing the project files: mkdir js-mongodb-connect && cd js-mongodb-connect Initialize the project: npm init -y Install the mongodb library: npm install mongodb To connect to MongoDB, import the mongodb library. Specify the database address in the constant uri and pass the address into the MongoClient class. const { MongoClient } = require('mongodb'); const uri = "mongodb://91.206.179.29:27017"; const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true }); async function connectToDatabase() { try { await client.connect(); console.log("Successfully connected to MongoDB!"); const database = client.db("myDatabase"); const collection = database.collection("myCollection"); const documents = await collection.find({}).toArray(); console.log("Documents found:", documents); } catch (error) { console.error("Error connecting to MongoDB:", error); } finally { await client.close(); console.log("Connection closed."); } } connectToDatabase(); ClickHouse and JavaScript To work with ClickHouse, use the clickhouse/client driver. Create a directory where we will store the project files: mkdir js-clickhouse-connect && cd js-clickhouse-connect Initialize the project: npm init -y Install the @clickhouse/client library: npm install @clickhouse/client To connect to ClickHouse, use the code below where we set the connection details and execute a simple SQL query that will return the first 10 records from the system table named system.tables: const { ClickHouse } = require('@clickhouse/client'); const client = new ClickHouse({ host: 'http://localhost:8123', username: 'default', password: 'PasswordforDefaultUser45435', database: 'default', }); async function connectAndQuery() { try { console.log('Successfully connected to ClickHouse Server!'); const rows = await client.query({ query: 'SELECT * FROM system.tables LIMIT 10', format: 'JSON', }).then((result) => result.json()); console.log('Query results:', rows); } catch (error) { console.error('Error Successfully connected to ClickHouse Server! or running the query:', error); } finally { console.log('Done.'); } } connectAndQuery(); Conclusion In today's article, we thoroughly explored how to connect to PostgreSQL, Redis, MongoDB, MySQL, and ClickHouse databases using Python, Go, and JavaScript. These languages can be used to create both web applications and microservices that utilize databases in their operation.
18 February 2025 · 23 min to read
Go

Working with Date and Time in Go Using the time Package

Go (Golang), like many other programming languages, has a built-in time package that provides special types and methods for working with dates and times. You can find comprehensive information about the time package in the official documentation. This guide will cover the basic aspects of working with time in Go.  All the examples shown were run on a cloud server provided by Hostman, using the Ubuntu 22.04 operating system and Go version 1.21.3. It is assumed that you are already familiar with the basics of Go and know how to run scripts using the appropriate interpreter command: go run script.go Parsing, Formatting, and Creating Dates Before getting started with time manipulation, it's important to understand a key feature of time formatting in Go. In most programming languages, date and time formats are specified using special symbols, which are replaced by values representing day, month, year, hour, minute, and second. However, Go approaches this differently. Instead of special symbols, it uses default date and time values represented by an increasing sequence of numbers: 01-02-03-04-05-06 This sequence of numbers represents: 1st month of the year (January) 2nd day of the month 3rd hour in 12-hour format (p.m.) 4th minute in 12-hour format (p.m.) 5th second in 12-hour format (p.m.) 6th year of the 21st century Thus, this results in the following time format: January 2nd, 3:04:05 PM, 2006 Or in another form: 02.01.2006 03:04:05 PM It is important to remember that this value is nothing more than a regular increasing sequence of numbers without any special significance. Therefore, this date and time act as a predefined layout for working with any explicitly specified date and time values. For example, here’s an abstract (not Go-specific) pseudocode example: currentTime = time.now() console.write("Current date: ", currentTime.format("%D.%M.%Y")) console.write("Current time: ", currentTime.format("%H:%M")) console.write("Current date and time: ", currentTime.format("%D.%M.%Y %H:%M")) In our pseudo-console, this would produce the following pseudo-output: Current date: 26.11.2024 Current time: 14:05 Current date and time: 26.11.2024 14:05 This is how date and time formatting works in most programming languages. In Go, however, the pseudocode would look like this: currentTime = time.now() console.write("Current date: ", currentTime.format("02.01.2006")) console.write("Current time: ", currentTime.format("03:04")) console.write("Current date and time: ", currentTime.format("02.01.2006 03:04")) The console output would be similar: Current date: 26.11.2024 Current time: 14:05 Current date and time: 26.11.2024 14:05 Here, the standard template values for date and time are automatically replaced with the actual date and time values. Additionally, template values have certain variations. For instance, you can specify the month 01 as Jan. Thanks to this approach, Go allows templates to be defined in a more intuitive and human-readable way. Parsing Working with time in Go starts by explicitly specifying it. This can be done using the time parsing function: package main import ( "fmt" // package for console I/O "time" // package for working with time "reflect" // package for determining variable types ) func main() { timeLayout := "2006-01-02" // time layout template timeValue := "2024-11-16" // time value to be parsed timeVariable, err := time.Parse(timeLayout, timeValue) // parsing time value using the template if err != nil { panic(err) // handling possible parsing errors } fmt.Println(timeVariable) // output the parsed time variable to the console fmt.Println(reflect.TypeOf(timeVariable)) // output the type of the time variable } When you run the script, the terminal will display the following output: 2024-11-16 00:00:00 +0000 UTC  time.Time Note that after parsing, a variable of type time.Time is created. This variable stores the parsed time value in its internal format. In the example shown, the time layout and value could be replaced with another equivalent format. func main() { timeLayout := "2006-Jan-02" timeValue:= "2024-Nov-16" ... The final result would remain the same. During parsing, an additional parameter can be specified to set the time zone, also known as the time offset or time zone: package main import ( "fmt" "time" ) func main() { // Local timeLocation, err := time.LoadLocation("Local") if err != nil { panic(err) } timeVariable, err := time.ParseInLocation("2006-01-02 15:04", "2024-11-16 07:45", timeLocation) if err != nil { panic(err) } fmt.Println("Local: ", timeVariable) // Asia/Bangkok timeLocation, err = time.LoadLocation("Asia/Bangkok") if err != nil { panic(err) } timeVariable, err = time.ParseInLocation("2006-01-02 15:04", "2024-11-16 07:45", timeLocation) if err != nil { panic(err) } fmt.Println("Asia/Bangkok: ", timeVariable) // Europe/Nicosia timeLocation, err = time.LoadLocation("Europe/Nicosia") if err != nil { panic(err) } timeVariable, err = time.ParseInLocation("2006-01-02 15:04", "2024-11-16 07:45", timeLocation) if err != nil { panic(err) } fmt.Println("Europe/Nicosia: ", timeVariable) } The console output of this script will be as follows: Local: 2024-11-16 07:45:00 +0000 UTC Asia/Bangkok: 2024-11-16 07:45:00 +0700 +07 Europe/Nicosia: 2024-11-16 07:45:00 +0300 EET Instead of explicitly creating a time zone variable, you can use a predefined constant: package main import ( "fmt" "time" ) func main() { // time.LoadLocation("Local") timeLocation, err := time.LoadLocation("Local") if err != nil { panic(err) } timeVariable, err := time.ParseInLocation("2006-01-02 15:04", "2024-11-16 07:45", timeLocation) if err != nil { panic(err) } fmt.Println(timeVariable) // time.Local timeVariable, err = time.ParseInLocation("2006-01-02 15:04", "2024-11-16 07:45", time.Local) if err != nil { panic(err) } fmt.Println(timeVariable) } In this case, the complete date and time values in both variants will be identical. 2024-11-16 07:45:00 +0000 UTC2024-11-16 07:45:00 +0000 UTC You can find a complete list of available time zones in the so-called Time Zone Database (tz database). Time zone identifiers are specified using two region names separated by a slash. For example: Europe/Nicosia Asia/Dubai US/Alaska Formatting We can format an already created time variable to represent its value as a specific text string. Thus, a variable of type time.Time has built-in methods for converting date and time into a string type. package main import ( "fmt" "time" ) func main() { timeLayout := "2006-01-02 15:04:05" timeValue := "2024-11-15 12:45:20" timeVariable, err := time.Parse(timeLayout, timeValue) if err != nil { panic(err) } fmt.Print("\r", "DATE", "\r\n") fmt.Println(timeVariable.Format("2006-01-02")) fmt.Println(timeVariable.Format("01/02/06")) fmt.Println(timeVariable.Format("01/02/2006")) fmt.Println(timeVariable.Format("20060102")) fmt.Println(timeVariable.Format("010206")) fmt.Println(timeVariable.Format("January 02, 2006")) fmt.Println(timeVariable.Format("02 January 2006")) fmt.Println(timeVariable.Format("02-Jan-2006")) fmt.Println(timeVariable.Format("Jan-02-06")) fmt.Println(timeVariable.Format("Jan-02-2006")) fmt.Println(timeVariable.Format("06")) fmt.Println(timeVariable.Format("Mon")) fmt.Println(timeVariable.Format("Monday")) fmt.Println(timeVariable.Format("Jan-06")) fmt.Print("\r", "TIME", "\r\n") fmt.Println(timeVariable.Format("15:04")) fmt.Println(timeVariable.Format("15:04:05")) fmt.Println(timeVariable.Format("3:04 PM")) fmt.Println(timeVariable.Format("03:04:05 PM")) fmt.Print("\r", "DATE and TIME", "\r\n") fmt.Println(timeVariable.Format("2006-01-02T15:04:05")) fmt.Println(timeVariable.Format("2 Jan 2006 15:04:05")) fmt.Println(timeVariable.Format("2 Jan 2006 15:04")) fmt.Println(timeVariable.Format("Mon, 2 Jan 2006 15:04:05 MST")) fmt.Print("\r", "PREDEFINED FORMATS", "\r\n") fmt.Println(timeVariable.Format(time.RFC1123)) // predefined format fmt.Println(timeVariable.Format(time.Kitchen)) // predefined format fmt.Println(timeVariable.Format(time.Stamp)) // predefined format fmt.Println(timeVariable.Format(time.DateOnly)) // predefined format } Running this script will output various possible date and time formats in the terminal: DATE 2024-11-15 11/15/24 11/15/2024 20241115 111524 November 15, 2024 15 November 2024 15-Nov-2024 Nov-15-24 Nov-15-2024 24 Fri Friday Nov-24 TIME 12:45 12:45:20 12:45 PM 12:45:20 PM DATE and TIME 2024-11-15T12:45:20 15 Nov 2024 12:45:20 15 Nov 2024 12:45 Fri, 15 Nov 2024 12:45:20 UTC PREDEFINED FORMATS Fri, 15 Nov 2024 12:45:20 UTC 12:45PM Nov 15 12:45:20 2024-11-15 Pay attention to the last few formats, which are predefined as constant values. These constants provide commonly used date and time formats in a convenient, ready-to-use form. You can find a complete list of these constants in the official documentation. time.Layout 01/02 03:04:05PM '06 -0700 time.ANSIC Mon Jan _2 15:04:05 2006 time.UnixDate Mon Jan _2 15:04:05 MST 2006 time.RubyDate Mon Jan 02 15:04:05 -0700 2006 time.RFC822 02 Jan 06 15:04 MST time.RFC822Z 02 Jan 06 15:04 -0700 time.RFC850 Monday, 02-Jan-06 15:04:05 MST time.RFC1123 Mon, 02 Jan 2006 15:04:05 MST time.RFC1123Z Mon, 02 Jan 2006 15:04:05 -0700 time.RFC3339 2006-01-02T15:04:05Z07:00 time.RFC3339Nano 2006-01-02T15:04:05.999999999Z07:00 time.Kitchen 3:04PM time.Stamp Jan _2 15:04:05 time.StampMilli Jan _2 15:04:05.000 time.StampMicro Jan _2 15:04:05.000000 time.StampNano Jan _2 15:04:05.000000000 time.DateTime 2006-01-02 15:04:05 time.DateOnly 2006-01-02 time.TimeOnly 15:04:05 Another common method to format date and time in Go is by converting it to Unix time.  package main import ( "fmt" "time" "reflect" ) func main() { timeVariable := time.Unix(350, 50) // set Unix time to 350 seconds and 50 nanoseconds from January 1, 1970, 00:00:00 fmt.Println("Time:", timeVariable) // display time in UTC format timeUnix := timeVariable.Unix() timeUnixNano := timeVariable.UnixNano() fmt.Println("Time (UNIX, seconds):", timeUnix) // display time in Unix format (seconds) fmt.Println("Time (UNIX, nanoseconds):", timeUnixNano) // display time in Unix format (nanoseconds) fmt.Println("Time (type):", reflect.TypeOf(timeUnix)) // display the variable type for Unix time } After running this script, the following output will appear in the terminal: Time: 1970-01-01 00:05:50.00000005 +0000 UTC Time (UNIX, seconds): 350 Time (UNIX, nanoseconds): 350000000050 Time (type): int64 Note that the variable created to store the Unix time value is of type int64, not time.Time. Thus, by using formatting, you can perform conversions between string-based time and Unix time and vice versa: package main import ( "fmt" "time" ) func main() { timeString, _ := time.Parse("2006-01-02 15:04:05", "2024-11-15 12:45:20") fmt.Println(timeString.Unix()) timeUnix := time.Unix(12345, 50) fmt.Println(timeUnix.Format("2006-01-02 15:04:05")) } The console output of this script will display the results of conversions to and from Unix time: 17316747201970-01-01 03:25:45 Creation In Go, there is a more straightforward way to create a time.Time variable by explicitly setting the date and time parameters: package main import ( "fmt" "time" ) func main() { timeLocation, _ := time.LoadLocation("Europe/Vienna") // year, month, day, hour, minute, second, nanosecond, time zone timeVariable := time.Date(2024, 11, 20, 12, 30, 45, 50, timeLocation) fmt.Print(timeVariable) } After running this script, the following output will appear in the terminal: 2024-11-20 12:30:45.00000005 +0100 CET Current Date and Time In addition to manually setting arbitrary dates and times, you can set the current date and time: package main import ( "fmt" "time" "reflect" ) func main() { timeNow := time.Now() fmt.Println(timeNow) fmt.Println(timeNow.Format(time.DateTime)) fmt.Println(timeNow.Unix()) fmt.Println(reflect.TypeOf(timeNow)) } After running this script, the following output will appear in the terminal: 2024-11-27 17:08:18.195495127 +0000 UTC m=+0.000035621 2024-11-27 17:08:18 1732727298 time.Time As you can see, the time.Now() function creates the familiar time.Time variable, whose values can be formatted arbitrarily. Extracting Parameters The time.Time variable consists of several parameters that together form the date and time: Year Month Day Weekday Hour Minute Second Nanosecond Time zone Go provides a set of methods to extract and modify each of these parameters. Most often, you will need to retrieve specific parameters from an already created time variable: package main import ( "fmt" "time" "reflect" ) func main() { timeLayout := "2006-01-02 15:04:05" timeValue := "2024-11-15 12:45:20" timeVariable, _ := time.Parse(timeLayout, timeValue) fmt.Println("Year:", timeVariable.Year()) fmt.Println("Month:", timeVariable.Month()) fmt.Println("Day:", timeVariable.Day()) fmt.Println("Weekday:", timeVariable.Weekday()) fmt.Println("Hour:", timeVariable.Hour()) fmt.Println("Minute:", timeVariable.Minute()) fmt.Println("Second:", timeVariable.Second()) fmt.Println("Nanosecond:", timeVariable.Nanosecond()) fmt.Println("Time zone:", timeVariable.Location()) fmt.Println("") fmt.Println("Year (type):", reflect.TypeOf(timeVariable.Year())) fmt.Println("Month (type):", reflect.TypeOf(timeVariable.Month())) fmt.Println("Day (type):", reflect.TypeOf(timeVariable.Day())) fmt.Println("Weekday (type):", reflect.TypeOf(timeVariable.Weekday())) fmt.Println("Hour (type):", reflect.TypeOf(timeVariable.Hour())) fmt.Println("Minute (type):", reflect.TypeOf(timeVariable.Minute())) fmt.Println("Second (type):", reflect.TypeOf(timeVariable.Second())) fmt.Println("Nanosecond (type):", reflect.TypeOf(timeVariable.Nanosecond())) fmt.Println("Time zone (type):", reflect.TypeOf(timeVariable.Location())) } The console output of this script will be: Year: 2024 Month: November Day: 15 Weekday: Friday Hour: 12 Minute: 45 Second: 20 Nanosecond: 0 Time zone: UTC Year (type): int Month (type): time.Month Day (type): int Weekday (type): time.Weekday Hour (type): int Minute (type): int Second (type): int Nanosecond (type): int Time zone (type): *time.Location Thus, you can individually retrieve specific information about the date and time without needing to format the output before displaying it in the console. Note the types of the retrieved variables — all of them have the int type except for a few: Month (time.Month) Weekday (time.Weekday) Time zone (*time.Location) The last one (time zone) is a pointer. Modification, Addition, and Subtraction Modification You cannot change the parameters of date and time directly in an already created time.Time variable. However, you can recreate the variable with updated values, thus changing the existing date and time: package main import ( "fmt" "time" ) func main() { timeVariable := time.Now() fmt.Println(timeVariable) // year, month, day, hour, minute, second, nanosecond, time zone timeChanged := time.Date(timeVariable.Year(), timeVariable.Month(), timeVariable.Day(), timeVariable.Hour() + 14, timeVariable.Minute(), timeVariable.Second(), timeVariable.Nanosecond(), timeVariable.Location()) fmt.Println(timeChanged) } When running this script, the following output will appear: 2024-11-28 14:35:05.287957345 +0000 UTC m=+0.0000391312024-11-29 04:35:05.287957345 +0000 UTC In this example, 14 hours were added to the current time. This way, you can selectively update the time values in an existing time.Time variable. Change by Time Zone Sometimes, it is necessary to determine what the specified date and time will be in a different time zone. For this, Go provides a special method: package main import ( "fmt" "time" ) func main() { locationFirst, _ := time.LoadLocation("Europe/Nicosia") timeFirst := time.Date(2000, 1, 1, 0, 0, 0, 0, locationFirst) fmt.Println("Time (Europe/Nicosia)", timeFirst) locationSecond, _ := time.LoadLocation("America/Chicago") timeSecond := timeFirst.In(locationSecond) // changing the time zone and converting the date and time based on it fmt.Println("Time (America/Chicago)", timeSecond) } The result of running the script will produce the following console output: Time (Europe/Nicosia) 2000-01-01 00:00:00 +0200 EET Time (America/Chicago) 1999-12-31 16:00:00 -0600 CST Thus, we obtain new date and time values, updated according to the newly specified time zone. Addition and Subtraction Go does not have separate methods for date and time addition. Instead, you can add time intervals to an already created time.Time variable: package main import ( "fmt" "time" ) func main() { // current time timeVariable := time.Now() fmt.Println(timeVariable) // adding 5 days (24 hours * 5 days = 120 hours) timeChanged := timeVariable.Add(120 * time.Hour) fmt.Println(timeChanged) // subtracting 65 days (24 hours * 65 days = 1560 hours) timeChanged = timeVariable.Add(-1560 * time.Hour) fmt.Println(timeChanged) } Running this script will give the following output: 2024-12-05 08:42:01.927334604 +0000 UTC m=+0.000035141 2024-12-10 08:42:01.927334604 +0000 UTC m=+432000.000035141 2024-10-01 08:42:01.927334604 +0000 UTC m=-5615999.999964859 Note that when subtracting a sufficient number of days from the time.Time variable, the month is also modified. Also, the time.Hour variable actually has a special type, time.Duration: package main import ( "fmt" "time" "reflect" ) func main() { fmt.Println(reflect.TypeOf(time.Hour)) fmt.Println(reflect.TypeOf(120* time.Hour)) } The output after running the script will be: time.Durationtime.Duration However, modifying the date and time by adding or subtracting a large number of hours is not very clear. In some cases, it is better to use more advanced methods for changing the time: package main import ( "fmt" "time" ) func main() { timeVariable := time.Now() fmt.Println(timeVariable) // year, month, day timeChanged := timeVariable.AddDate(3, 2, 1) fmt.Println(timeChanged) // day timeChanged = timeChanged.AddDate(0, 0, 15) fmt.Println(timeChanged) // year, month timeChanged = timeChanged.AddDate(5, 1, 0) fmt.Println(timeChanged) // -year, -day timeChanged = timeChanged.AddDate(-2, 0, -10) fmt.Println(timeChanged) } After running this script, the output will look like this: 2024-11-28 17:51:45.769245873 +0000 UTC m=+0.000024921 2028-01-29 17:51:45.769245873 +0000 UTC 2028-02-13 17:51:45.769245873 +0000 UTC 2033-03-13 17:51:45.769245873 +0000 UTC 2031-03-03 17:51:45.769245873 +0000 UTC Subtraction Unlike addition, Go has specialized methods for subtracting one time.Time variable from another. package main import ( "fmt" "time" "reflect" ) func main() { timeFirst := time.Date(2024, 6, 14, 0, 0, 0, 0, time.Local) timeSecond := time.Date(2010, 3, 26, 0, 0, 0, 0, time.Local) timeDeltaSub := timeFirst.Sub(timeSecond) // timeFirst - timeSecond timeDeltaSince := time.Since(timeFirst) // time.Now() - timeFirst timeDeltaUntil := time.Until(timeFirst) // timeFirst - time.Now() fmt.Println("timeFirst - timeSecond =", timeDeltaSub) fmt.Println("time.Now() - timeFirst =", timeDeltaSince) fmt.Println("timeFirst - time.Now() =", timeDeltaUntil) fmt.Println("") fmt.Println(reflect.TypeOf(timeDeltaSub)) fmt.Println(reflect.TypeOf(timeDeltaSince)) fmt.Println(reflect.TypeOf(timeDeltaUntil)) } Console output: timeFirst - timeSecond = 124656h0m0s time.Now() - timeFirst = 4029h37m55.577746026s timeFirst - time.Now() = -4029h37m55.577746176s time.Duration time.Duration time.Duration As you can see, the result of the subtraction is the familiar time.Duration type variable. In fact, the main function for finding the difference is time.Time.Sub(), and the other two are just its derivatives: package main import ( "fmt" "time" ) func main() { timeVariable := time.Date(2024, 6, 14, 0, 0, 0, 0, time.Local) fmt.Println(time.Now().Sub(timeVariable)) fmt.Println(time.Since(timeVariable)) fmt.Println("") fmt.Println(timeVariable.Sub(time.Now())) fmt.Println(time.Until(timeVariable)) } Console output: 4046h10m53.144212707s 4046h10m53.144254987s -4046h10m53.144261117s -4046h10m53.144267597s You can see that the results of these described functions are identical. time.Time.Since() = time.Now().Sub(timeVariable) time.Time.Until() = timeVariable.Sub(time.Now()) Time Durations Individual time intervals (durations) in the time package are represented as a special variable of type time.Duration. Unlike time.Time, they store not full date and time but time intervals. With durations, you can perform some basic operations that modify their time parameters. Parsing Durations A duration is explicitly defined using a string containing time parameters: package main import ( "fmt" "time" ) func main() { // hours, minutes, seconds durationHMS, _ := time.ParseDuration("4h30m20s") fmt.Println("Duration (HMS):", durationHMS) // minutes, seconds durationMS, _ := time.ParseDuration("6m15s") fmt.Println("Duration (MS):", durationMS) // hours, minutes durationHM, _ := time.ParseDuration("2h45m") fmt.Println("Duration (HM):", durationHM) // hours, seconds durationHS, _ := time.ParseDuration("2h10s") fmt.Println("Duration (HS):", durationHS) // hours, minutes, seconds, milliseconds, microseconds, nanoseconds durationFULL, _ := time.ParseDuration("6h50m40s30ms4µs3ns") fmt.Println("Full Duration:", durationFULL) } Output of the script: Duration (HMS): 4h30m20s Duration (MS): 6m15s Duration (HM): 2h45m0s Duration (HS): 2h0m10s Full Duration: 6h50m40.030004003s Note the last duration, which contains all possible time parameters in decreasing order of magnitude—hours, minutes, seconds, milliseconds, microseconds, and nanoseconds. During parsing, each parameter is specified using the following keywords: Hours — h Minutes — m Seconds — s Milliseconds — ms Microseconds — µs Nanoseconds — ns Moreover, the order of specifying duration parameters does not affect it: package main import ( "fmt" "time" ) func main() { duration, _ := time.ParseDuration("7ms20s4h30m") fmt.Println("Duration:", duration) } Terminal output: Duration: 4h30m20.007s Formatting Durations In Go, we can represent the same duration in different units of measurement: package main import ( "fmt" "time" "reflect" ) func main() { duration, _ := time.ParseDuration("4h30m20s") fmt.Println("Duration:", duration) fmt.Println("") fmt.Println("In hours:", duration.Hours()) fmt.Println("In minutes:", duration.Minutes()) fmt.Println("In seconds:", duration.Seconds()) fmt.Println("In milliseconds:", duration.Milliseconds()) fmt.Println("In microseconds:", duration.Microseconds()) fmt.Println("In nanoseconds:", duration.Nanoseconds()) fmt.Println("") fmt.Println(reflect.TypeOf(duration.Hours())) fmt.Println(reflect.TypeOf(duration.Minutes())) fmt.Println(reflect.TypeOf(duration.Seconds())) fmt.Println(reflect.TypeOf(duration.Milliseconds())) fmt.Println(reflect.TypeOf(duration.Microseconds())) fmt.Println(reflect.TypeOf(duration.Nanoseconds())) } Output of the script: Duration: 4h30m20s In hours: 4.5055555555555555 In minutes: 270.3333333333333 In seconds: 16220 In milliseconds: 16220000 In microseconds: 16220000000 In nanoseconds: 16220000000000 float64 float64 float64 int64 int64 int64 As you can see, the parameters for hours, minutes, and seconds are of type float64, while the rest are of type int. Conclusion This guide covered the basic functions for working with dates and times in the Go programming language, all of which are part of the built-in time package. Thus, Go allows you to: Format dates and times Convert dates and times Set time zones Extract specific date and time parameters Set specific date and time parameters Add and subtract dates and times Execute code based on specific time settings For more detailed information on working with the time package, refer to the official Go documentation. In addition, you can deploy Go applications (such as Beego and Gin) on our app platform.
28 January 2025 · 19 min to read
Go

Variables in Go

Variables are named values stored in specific areas of memory and used during program execution. Go (also known as Golang) is a statically typed programming language. This means that once a variable is declared, its type is fixed and cannot be changed. Variables can have various types, each with its own purpose and characteristics.Go provides several basic data types, which form the foundation of the language's logic: Integer Floating-point String Boolean Additionally, Go supports composite data types: Arrays Slices Structures Maps There are also several auxiliary types: Pointers Interfaces Besides these, Go (similar to C++) includes a Standard Library (std) containing many predefined types. You can find more detailed information about variable types in Go in a separate article. For instructions on installing Go on Linux, Windows, or macOS, refer to the Hostman guides.  All the code examples in this tutorial were tested using Go version 1.21.3. Compiling and Running Code All the code examples in this guide are run in separate files with the .go extension. First, create a new file: sudo nano example.go Next, fill it with code inside the main() function, including any necessary modules: package main import "fmt" func main() { // start of example var number int = 10 fmt.Println(number) // end of example } Then run the file: go run example.go Declaring a Variable There are different ways to declare a variable in Go before using it—ranging from a full form, explicitly specifying the parameters (or multiple parameters) of the variable, to a shorthand form that uses automatic type inference and initialization. The choice of declaration method depends on the context. However, it’s generally recommended to use the most concise and automatic form whenever possible, as this reduces the likelihood of programmer errors by shifting some of the responsibility to the language's interpreter. Using the var Keyword The most explicit way to declare a variable in Golang is by using the var keyword, followed by the variable name, type, and value: var some_variable int = 5 However, if the variable is initialized with a value, you can omit the explicit type: var some_variable = 5 You can also declare a variable without assigning a value, but in this case, you must specify the type: var some_variable intsome_variable = 5 In all of these examples: var — the keyword for declaring a variable some_variable — the variable's name int — the variable's type 5 — the variable's value For example, this is how you can declare string variables: var some_name string = "John" The following declaration will result in an error: // ERROR: no value or type specified during declarationvar some_namesome_name = "John" It’s important to note that type inference is only possible during the initial declaration of the variable when the interpreter allocates the appropriate amount of memory for its value. Short Form := Despite Go's strict static typing, it allows variables to be declared in a more concise form without explicitly specifying their parameters: some_variable := 5 In this case, the interpreter understands that it needs to automatically infer the variable type based on the assigned value. However, this shorthand declaration is only allowed inside a function (including main()); it cannot be used outside a function: package main // ERROR: short form declaration outside of a function some_variable := 5 func main() { // OK: short form declaration inside a function other_variable := 10 } It’s important to understand the distinction between declaring a variable (with initialization) and assigning a value to it: package main func main() { some_variable := 5 // this is declaration and initialization (colon is present) some_variable = 50 // this is assignment (no colon) other_variable = 7 // ERROR: this is assignment (no colon) to an undeclared variable } For example, you can declare (and initialize) several variables sequentially: age := 50 // variable of type int name := "John" // variable of type string occupation := "Just a guy" // variable of type string height := 190.5 // variable of type float32 You cannot use the := operator together with the var keyword. Doing so will result in an error: var someVariable int := 5 // ERRORvar someVariable := 5 // ERROR Excluding the var keyword but still explicitly specifying the type will still result in an error: someVariable int := 5 // ERROR Multiple Variables In Go, you can declare multiple variables in one line or block. For example, you can use the var keyword with a single type for all declared variables: var width, height, depth int = 100, 200, 300 You can also separate the declaration of variables and their assignment: var width, height, depth intwidth, height, depth = 100, 200, 300 If the variable types differ, the interpreter can automatically infer their types: var name, age, fired = "John", 50, false Similarly, you can use the short form for multiple variables: name, age, fired := "John", 50, false In this case, there is no var keyword, nor are the types of the variables specified. Another way to declare multiple variables is by using a block: var ( name string = "John" age int = 50 height float64 = 190 fired bool = false ) By the way, you can format block declarations using spaces in such a way that names, types, and values align in columns, improving code readability: var ( name string = "John" age int = 50 height float64 = 190.5 fired bool = false ) The block declaration has no particular utility significance. It’s just syntactic sugar that: Improves code readability by grouping important variables in one place. Improves code cleanliness by avoiding repeated use of the var keyword for each variable. Improves code maintainability by simplifying the search and modification of variable parameters. Thus, block declaration is justified only when you need to group several key variables, simplifying their visual perception in a code editor. No Initialization In Go, it is possible to create a variable without initializing it. In this case, the variable is assigned a zero value corresponding to the specified type: For int, float32, float64: 0, 0.0, 0.0 For bool: false For string: "" For pointers: nil We can demonstrate this behavior of Go regarding variable declaration and initialization in the following script: package main import "fmt" func main() { // Integer var numberInt int fmt.Println("Integer:", numberInt) // Floating-point number var numberFloat float32 fmt.Println("Floating-point number:", numberFloat) // String var text string fmt.Println("String:", text) // Boolean var condition bool fmt.Println("Boolean:", condition) // Array var array [5]int fmt.Println("Array:", array) // Slice var cut []int fmt.Println("Slice:", cut) // Struct type S struct { name string size int address string } var structure S fmt.Println("Struct:", structure) // Map var dictionary map[int]int fmt.Println("Map:", dictionary) // Pointer var pointer *int fmt.Println("Pointer:", pointer) } The console output will be as follows: Integer: 0 Floating-point number: 0 String: Boolean: false Array: [0 0 0 0 0] Slice: [] Struct: { 0} Map: map[] Pointer: <nil> As you can see, variables of different types are automatically initialized with zero (or empty) values wherever possible. Naming Conventions In Golang, variable names can either start with a Latin letter or an underscore (_): onething := 123 // OK Onething := 123 // OK _onething := 123 // OK __onething := 123 // OK 1thing := 123 // ERROR Additionally, variable names have a functional feature: names starting with an uppercase letter are visible in other packages, while names starting with a lowercase letter are not. There are also several universal naming conventions across programming languages, including Go: Snake Case Camel Case Pascal Case Kebab Case (not supported in Go) Snake Case In Snake Case, the variable name looks like this: some_random_variable := 123 // lowercaseSOME_RANDOM_VARIABLE := 123 // uppercase Camel Case In Camel Case, the variable name looks like this: someRandomVariable := 12 Pascal Case In Pascal Case, the variable name looks like this: SomeRandomVariable := 123 Kebab Case In Kebab Case, the variable name looks like this: // ERRORsome-random-variable := 123 // lowercaseSOME-RANDOM-VARIABLE := 123 // uppercase However, Go doesn't support the Kebab Case style due to the hyphen character, which is reserved for the subtraction operation. Example: Declaring Multiple Variables Let’s further explore all the aforementioned ways of declaring variables in Golang in this script example: package main import "fmt" func main() { // Explicit declaration with type specification var age int = 50 fmt.Println("Age:", age) // Explicit declaration with type inference var height = 190.5 fmt.Println("Height:", height) // Short declaration name := "John" fmt.Println("Name:", name) // Explicit declaration of multiple variables var width, depth int = 100, 200 fmt.Println("Width:", width, "Depth:", depth) // Explicit declaration without initialization var distance int fmt.Println("Distance:", distance) // Block declaration of multiple variables var ( occupation string = "Welder" category float32 = 3.4 license bool ) fmt.Println("Occupation:", occupation, "Category:", category, "License:", license) } The result of running this code will be the following output in the console: Age: 50 Height: 190.5 Name: John Width: 100 Depth: 200 Distance: 0 Occupation: Welder Category: 3.4 License: false The var keyword is required for explicit variable declaration, especially in the global scope. The := operator is used for short variable declarations, particularly within functions. The block () syntax is used for readable declaration of multiple variables. It's important to remember that Go emphasizes minimalism and concise syntax. Therefore, the most compact form of notation should be used wherever possible. This reduces errors and issues while maintaining the cleanliness and readability of the code. Variable Initialization Typically, when a variable is declared, it is manually initialized with a specific value. The initialization of different types has syntactic differences. Number Numerical variables are initialized by assigning a numerical value, which is syntactically simple: // int var someNumber int = 5 // float32 otherNumber := 10.0 A number can be initialized with another number: // int var someNumber int = 5 var otherNumber int = someNumber // int oneMoreNumber := someNumber String String variables are initialized by assigning a sequence of characters enclosed in double quotes: // stringvar someString string = "Some programmer was here" A string can also be initialized with another string: // string var someString string = "Some programmer was here" var otherString string = someString // string oneMoreString := someString Boolean Initializing boolean variables is similar to initializing numeric and string variables, except that the value used is the keyword true or false: // boolvar someBool bool = true Similarly, boolean variables can be initialized with other boolean variables: // bool var someBool bool = true var otherBool bool = someBool // bool oneMoreBool := someBool Array There are several ways to initialize an array. The simplest one is through sequential access to the elements: // array var languages [3]string languages[0] = "Golang" languages[1] = "Python" languages[2] = "Rust" A more complex method is using a composite literal. A composite literal is a compact syntax for initializing any composite (struct-like) type, which avoids assigning each element individually. Thus, the array can be initialized in one step: var languages = [3]string{"Golang", "Python", "Rust"} Or using the shorthand form: languages := [3]string{"Golang", "Python", "Rust"} You can also partially initialize array elements: // array size 5, but only 3 elements initialized languages := [5]string{"Golang", "Python", "Rust"} languages[3] = "Java" languages[4] = "C++" To make the initialization of a large array more readable, you can format it like this: languages := [5]string{ "Golang", "Python", "Rust", "Java", "C++", // the comma at the end is REQUIRED } By the way, an array can be initialized with another array, copying all of its elements: languages := [3]string{"Golang", "Python", "Rust"}otherLanguages := languages It’s important to understand that copying an array also occurs when it is passed to a function: package main import "fmt" func change(languages [5]string) { for i := range languages { languages[i] = "[" + languages[i] + "]" } } func main() { languages := [5]string{ "Golang", "Python", "Rust", "Java", "C++", } change(languages) fmt.Println(languages) } The output in the console will be: [Golang Python Rust Java C++] Thus, only the copy of the array inside the change() function was modified, not the original array from the main() function. However, explicit initialization of an array with another array is possible only if both arrays have the same length and type: languages := [3]string{"Golang", "Python", "Rust"} var otherLanguages [3]string = languages // OK var oneMoreLanguages [4]string = languages // ERROR Additionally, in Go, you can create arrays from an arbitrary number of other arrays. You can initialize elements of such arrays both sequentially: var matrix [2][2]string matrix[0][0] = "a" matrix[0][1] = "b" matrix[1][0] = "c" matrix[1][1] = "d" Or using a composite literal: var matrix = [2][2][2]string{{{"a", "b"}, {"c", "d"}}, {{"e", "f"}, {"g", "h"}}} As shown, the second option takes up less space, but the syntax is more complex. Slice A slice is initialized the same way as an array: var languages = []string{"Golang", "Python", "Rust"} However, unlike an array, a slice can be initialized with another slice of arbitrary length: var languages = []string{"Golang", "Python", "Rust"}var otherLanguages []string = languages Map Maps are initialized using a composite literal with the type of the key and value specified. The content is listed using commas and separated by a colon: var languages = map[string]string{"first": "Golang", "second": "Python", "third": "Rust"} You can also use the shorthand declaration and a more readable initialization format: languages := map[string]string{ "first": "Golang", "second": "Python", "third": "Rust", // the comma at the end is MANDATORY } However, initializing a map with another map does not copy the elements; instead, it makes them shared: package main import "fmt" func main() { languages := map[string]string{"first": "Golang", "second": "Python", "third": "Rust"} otherLanguages := languages fmt.Println(languages) fmt.Println(otherLanguages) otherLanguages["first"] = "C++" fmt.Println(languages) fmt.Println(otherLanguages) delete(otherLanguages, "second") fmt.Println(languages) fmt.Println(otherLanguages) } The console output of this example will be: map[first:Golang second:Python third:Rust] map[first:Golang second:Python third:Rust] map[first:C++ second:Python third:Rust] map[first:C++ second:Python third:Rust] map[first:C++ third:Rust] map[first:C++ third:Rust] Pointer Pointers can only be initialized with the address of a variable of the same type: var variable int = 15var pointer *int = &variable The ampersand (&) symbol is used to get the address of any variable: package main import "fmt" func main() { var variable int = 15 var pointer *int = &variable fmt.Println(pointer) } The console output of this example will look something like: 0xc000104040 You can also use shorthand notation to initialize pointers: variable := 15pointer := &variable To access the value stored at the address of a pointer, you need to dereference it using the asterisk (*): package main import "fmt" func main() { var variable int = 15 var pointer *int = &variable fmt.Println(*pointer) } In this case, the console output will show: 15 Thus, you can assign new values to a variable located at the address of the pointer: package main import "fmt" func main() { var variable int = 15 var pointer *int = &variable *pointer = 5 fmt.Println(*pointer) } The console will display: 5 Finally, a pointer can be initialized with an anonymous object in memory. This is done using the new() function, which returns the address of the allocated memory: variable := new(int)*variable = 15 You don't need to manually delete the allocated memory — the garbage collector automatically handles this. Structure A structure can be initialized either with explicitly specified values in order: type something struct { first string second int } var structure something = something{"John", 15} Or with explicitly specified values by key names: type something struct { first string second int } var structure something = something{second: 15, first: "John"} Alternatively, you can choose not to specify any values, which will automatically initialize all fields to their zero values: package main import "fmt" type something struct { first string second int } func main() { var structure something = something{} fmt.Println(structure) structure.first = "John" structure.second = 15 fmt.Println(structure) } In this case, the console output will be: { 0} {John 15} Branching Based on Variables Variables play a central role in branching. Different parts of the program's code are executed based on their values (conditions). if/else The most basic conditional construct is created using the if/else statements. Here's the simplest condition: a := 5 b := 10 if a < b { fmt.Println("A is less than B") } For example, you can use a simple condition to check a pointer: var pointer *int if pointer == nil { fmt.Println("No address") } A more complex form would look like this: a := 10 b := 5 if a < b { fmt.Println("A is less than B") } else { fmt.Println("A is greater than B") } You can create even more complex constructs by combining else and if: a := 10 b := 5 if a < b { fmt.Println("A is less than B") } else if a > b { fmt.Println("A is greater than B") } else { fmt.Println("A is equal to B") } Multiple if/else expressions can be used: a := 12 if a < 5 { fmt.Println("A is less than 5") } else if a < 10 { fmt.Println("A is less than 10") } else if a < 20 { fmt.Println("A is less than 20") } else { fmt.Println("A is in superposition") } switch Another way to branch is using the switch construct, where possible values of a variable are defined, and actions are performed if there's a match: a := 1 switch a { case 0: fmt.Println("A is 0") case 1: fmt.Println("A is 1") case 2: fmt.Println("A is 2") } The default section can be used to define an action that runs if no match occurs: a := 3 switch a { case 0: fmt.Println("A is 0") case 1: fmt.Println("A is 1") case 2: fmt.Println("A is 2") default: fmt.Println("A is in superposition") } You can also combine multiple possible matches into one section: a := 1 switch a { case 0, 1, 2: fmt.Println("A is either 0, 1, or 2") default: fmt.Println("A is in superposition") } Useful Functions Go has many utility functions for working with variables. In this guide, we'll cover just the basic ones. Environment Variables Go provides special system functions that allow you to set and get environment variables: package main import ( "fmt" "os" ) func main() { os.Setenv("SOMEVAR", "1") // Set an environment variable fmt.Println("SOMEVAR:", os.Getenv("SOMEVAR")) // Read an environment variable } Time Variables Often, the program logic requires measuring time. Go has a corresponding tool for this — the time type. Time is a broad topic by itself. To learn more about the time package, you can check the official documentation. This guide will show how to get the current time in different formats: package main import ( "fmt" "time" ) func main() { fmt.Println("Current time:", time.Now()) fmt.Println("Current time (UTC):", time.Now().UTC()) fmt.Println("Current time (Unix):", time.Now().Unix()) } The console output will look something like this: Current time: 2009-11-10 23:00:00 +0000 UTC m=+0.000000001 Current time (UTC): 2009-11-10 23:00:00 +0000 UTC Current time (Unix): 1257894000 You can also specify specific time parameters: package main import ( "fmt" "time" ) func main() { timeNow := time.Now() fmt.Println("Full time:", timeNow) fmt.Println("Year:", timeNow.Year()) fmt.Println("Month:", timeNow.Month()) fmt.Println("Day:", timeNow.Day()) fmt.Println("Hour:", timeNow.Hour()) fmt.Println("Minutes:", timeNow.Minute()) fmt.Println("Seconds:", timeNow.Second()) } In this case, the console output will be: Full time: 2024-11-15 23:46:09.157929822 +0000 UTC m=+0.000031801 Year: 2024 Month: November Day: 15 Hour: 23 Minutes: 23 Seconds: 9 Adding and Removing Elements from a Slice You can add elements to slices: var languages = []string{"Golang", "Python", "Rust"} languages = append(languages, "Java", "C++") fmt.Println(languages) This will append "Java" and "C++" to the languages slice. You can also remove elements from slices: var languages = []string{"Golang", "Python", "Rust"} // Remove the 2nd element (index 1) n := 1 languages = append(languages[:n], languages[n+1:]...) fmt.Println(languages) In this example, the second element is removed from the languages slice using slice operators, which create a new sequence from parts of the original slice. Here’s an example of slicing a sequence: package main import "fmt" func main() { var sequence = []string{"One", "Two", "Three", "Four", "Five"} newSequence := sequence[1:4] // Elements from index 1 to 3 become the new slice fmt.Println(newSequence) } The output in the console will be: [Two Three Four] Checking the Type of a Variable You can check the type of a variable using the TypeOf() function from the reflect package: package main import ( "fmt" "reflect" // Package to determine the type ) func main() { variableString := "string" variableInt := 5 variableFloat64 := 1.5 variableBool := true fmt.Println(reflect.TypeOf(variableString)) fmt.Println(reflect.TypeOf(variableInt)) fmt.Println(reflect.TypeOf(variableFloat64)) fmt.Println(reflect.TypeOf(variableBool)) } The console output for this example will be: string int float64 bool Variables in Strings Often, you need to insert a variable into a string. There are several ways to do this: package main import "fmt" func main() { // METHOD 1 stringPre := "human-readable" stringEnd1 := fmt.Sprintf("This is a %s string", stringPre) fmt.Println(stringEnd1) // METHOD 2 stringEnd2 := "This is " + stringPre + " string" fmt.Println(stringEnd2) } The output in the console will be: This is a human-readable stringThis is a human-readable string You can also combine numeric variables with strings: package main import "fmt" func main() { name := "John" age := 50 fmt.Printf("Hi, my name is %v and I'm %v years old.\n", name, age) } The output will be: Hi, my name is John and I'm 50 years old. Conclusion Like in most other programming languages, variables in Go are essential for storing data. Since data types differ from each other, Golang variables have several basic types, each having a specific representation in the computer's memory. In this guide, we only covered the basic ways to work with variables. You can find more detailed (and comprehensive) information about types and their specifics in the official Golang documentation. Additionally, the official Go package manager catalog provides information on many useful modules available for import into your project. One such module is the Standard Library. Check out our app platform to deploy Go applications (such as Beego and Gin). 
27 January 2025 · 19 min to read

Do you have questions,
comments, or concerns?

Our professionals are available to assist you at any moment,
whether you need help or are just unsure of where to start.
Email us
Hostman's Support