Share & grow the world's code base!

Delve into a community where programmers unite to discover code snippets, exchange skills, and enhance their programming proficiency. With abundant resources and a supportive community, you'll find everything essential for your growth and success.

35 snippets
  • Simple TCP client in Go

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"net"
    	"time"
    )
    
    type Client struct {
    	conn net.Conn
    }
    
    func (c *Client) Write(content string) error {
    	_, err := c.conn.Write([]byte(content + "\n"))
    
    	return err
    }
    
    func (c *Client) Read() (string, error) {
    	reader := bufio.NewReader(c.conn)
    
    	return reader.ReadString('\n')
    }
    
    func (c *Client) Close() error {
    	return c.conn.Close()
    }
    
    // create tcp client
    func getClient(address string) (*Client, error) {
    	// try to resolve address
    	_, err := net.ResolveTCPAddr("tcp", address)
    
    	if err != nil {
    		return nil, err
    	}
    
    	// create tcp connection with 5s timeout 
    	conn, err := net.DialTimeout("tcp", address, 5*time.Second)
    
    	if err != nil {
    		return nil, err
    	}
    
    	conn.SetReadDeadline(time.Now().Add(5 * time.Second))
    	conn.SetWriteDeadline(time.Now().Add(5 * time.Second))
    
    	return &Client{conn: conn}, nil
    }
    
    func main() {
    	// see https://tcpbin.com/
    	client, err := getClient("tcpbin.com:4242")
    
    	if err != nil {
    		panic(err)
    	}
    
    	// close the connection at the end
    	defer client.Close()
    
    	// send request to tcpbin.com echo server
    	err = client.Write("Hello, World!!!")
    
    	if err != nil {
    		panic(err)
    	}
    
    	// read response from tcpbin.com echo server
    	content, err := client.Read()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Print(content)
    }
    
    // $ go run main.go 
    // Hello, World!!!

    This example should give a basic understanding of how to create a TCP client in Go.

  • Parsing YAML Files in Go Without a Struct Definition

    package main
    
    import (
     "fmt"
     "os"
    
     "gopkg.in/yaml.v3"
    )
    
    func main() {
        dataMap := make(map[string]interface{})
        yamlFile, err := os.ReadFile("example.yaml")
     
        if err != nil {
            panic(err)
        }
    
        err = yaml.Unmarshal(yamlFile, dataMap)
        
        if err != nil {
            panic(err)
        }
        
        fmt.Println(dataMap)
    }

    If you want to parse a YAML file into a Go map but are having trouble defining the appropriate struct, there are a couple of alternatives you can use. In Go, you can read a YAML file without needing to define a struct by using the `map[string]interface{}` type. This method lets you load the YAML content into a nested map structure, bypassing the need for a specific struct definition.

  • Detecting symbolic link in Go

    package main
    
    import (
    	"fmt"
    	"os"
    	"path/filepath"
    )
    
    func IsSymlink(path string) (bool, error) {
    	var isSymlink bool
    	stat, err := os.Lstat(path)
    
    	if err != nil {
    		return isSymlink, err
    	}
    
    	isSymlink = (stat.Mode() & os.ModeSymlink) == os.ModeSymlink
    
    	return isSymlink, nil
    }
    
    func main() {
    	// create temporary file
    	tmpFile, err := os.CreateTemp("", "tmpfile")
    
    	if err != nil {
    		panic(err)
    	}
    
    	defer os.Remove(tmpFile.Name())
    
    	fmt.Println("Temp file name:", tmpFile.Name())
    
    	symlinkPath := filepath.Join(os.TempDir(), "tmpsymlink")
    
    	// create symlink
    	err = os.Symlink(tmpFile.Name(), symlinkPath)
    
    	if err != nil {
    		panic(err)
    	}
    
    	defer os.Remove(symlinkPath)
    
    	// check if file is symlink
    	isSymlink, err := IsSymlink(symlinkPath)
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Printf("'%s' is symlink: %v", symlinkPath, isSymlink)
    
    }
    
    // $ go run main.go 
    // Temp file name: /tmp/tmpfile1471080551
    // '/tmp/tmpsymlink' is symlink: true

    An example of determining whether a file is a symlink.

  • Pretty Printing Structs in Go

    package main
    
    import (
        "fmt"
        "encoding/json"
    )
    
    type User struct {
        FirstName string `json:"firstname"`
        SecondName string `json:"secondname"`
        Salary int `json:"salary"`
    }
    
    func main() {
        user := User{
            FirstName: "John",
            SecondName: "Doe",
            Salary: 5000,
        }
    
        b, err := json.MarshalIndent(user, "", "  ")
        
        if err != nil {
            fmt.Println(err)
        }
        
        fmt.Print(string(b))
    }

    We can utilize the `json.MarshalIndent` function, which requires the interface we want to marshal, along with a prefix string and an indent string. In this case, we won't use a prefix, but we will set the indent to two empty spaces.

  • Examples of generics in Go

    package main
    
    import (
    	"fmt"
    	"sort"
    
    	"golang.org/x/exp/constraints"
    )
    
    // Keys retrieves the keys from the map m as a slice.
    // The order of the keys is unpredictable.
    // This function includes two type parameters: K and V.
    // Map keys must be comparable, meaning K must satisfy the
    // predeclared constraint of being comparable. Values in the
    // map can be of any type.
    func Keys[K comparable, V any](m map[K]V) []K {
    	r := make([]K, 0, len(m))
    
    	for k := range m {
    		r = append(r, k)
    	}
    
    	return r
    }
    
    // Filter removes values from a slice based on a filter function.
    // It returns a new slice containing only the elements of s
    // for which the function f returns true.
    func Filter[T any](s []T, f func(T) bool) []T {
    	var r []T
    	for _, v := range s {
    		if f(v) {
    			r = append(r, v)
    		}
    	}
    	return r
    }
    
    // Sort sorts a slice of any orderable type T.
    // The constraints.Ordered constraint in the Sort() function ensures
    // that it can sort values of any type that supports the operators <, <=, >=, and >.
    func Sort[T constraints.Ordered](s []T) {
    	sort.Slice(s, func(i, j int) bool {
    		return s[i] < s[j]
    	})
    }
    
    // Define type Number with constraints
    type Number interface {
    	constraints.Float | constraints.Integer
    }
    
    // Multiply number by 2
    func Double[T Number](value T) T {
    	return value * 2
    }
    
    // Sum calculates the total of the values in a map that contains numeric or float values.
    func Sum[K comparable, V Number](m map[K]V) V {
    	var s V
    	for _, v := range m {
    		s += v
    	}
    	return s
    }
    
    // Scale returns a copy of s with each element multiplied by c.
    func Scale[S ~[]E, E constraints.Integer](s S, c E) S {
    	r := make(S, len(s))
    	for i, v := range s {
    		r[i] = v * c
    	}
    	return r
    }
    
    func main() {
    	k := Keys(map[int]int{1: 2, 2: 4})
    	fmt.Println(k)
    
    	sum := Sum(map[int]int{1: 2, 2: 4})
    	fmt.Println(sum)
    
    	s := []int{1, 2, 3, 7, 5, 22, 18}
    
    	evens := Filter(s, func(i int) bool { return i%2 == 0 })
    	fmt.Println(evens)
    
    	Sort(s)
    	fmt.Println(s)
    
    	fmt.Println(Double(23))
    	fmt.Println(Double(23.23))
    
    	intValues := map[string]int64{
    		"first":  23,
    		"second": 565,
    		"third":  755,
    	}
    
    	fmt.Println(Sum(intValues))
    
    	sc := Scale([]int{1, 2, 3}, 2)
    	fmt.Println(sc)
    }

    Generics is a feature that enables you to write reusable and type-safe code. With generics, you can create functions and data structures that operate on multiple types without requiring runtime type assertions or type casting. Here are examples of using generics in Go.

  • Iterators in Go

    package main
    
    import (
    	"fmt"
    	"iter"
    )
    
    // As long as the loop continues to run, yield will keep returning true,
    // indicating that more values exist.
    // However, if the loop terminates (for instance, due to a break or return),
    // yield will return false.
    // This allows to perform any necessary cleanup.
    func generateFibonacci() iter.Seq[int] {
    	return func(yield func(int) bool) {
    		a, b := 1, 1
    
    		for {
    			if !yield(a) {
    				fmt.Println("Stop sequence")
    				return
    			}
    
    			a, b = b, a+b
    		}
    	}
    }
    
    func main() {
    	for v := range generateFibonacci() {
    		fmt.Println(v)
    
    		if v > 10 {
    			break
    		}
    	}
    }
    
    // $ go run main.go 
    // 1
    // 1
    // 2
    // 3
    // 5
    // 8
    // 13
    // Stop sequence

    A Golang iterator is a function that “yields” one result at a time, rather than computing an entire set of results and returning them all at once. When you use an iterator in a for loop with a range expression, the loop executes once for each value returned by the iterator. Here is an example of range over iterator in Go.

  • Decompress tag.gz file in Go

    package main
    
    import (
    	"archive/tar"
    	"compress/gzip"
    	"fmt"
    	"io"
    	"os"
    	"path/filepath"
    
    	"github.com/unknwon/com"
    )
    
    func ExtractTarGz(file, folder string) error {
    	// open specified file
    	gzipStream, err := os.Open(file)
    
    	if err != nil {
    		return err
    	}
    
    	// create uncompressed stream reader
    	uncompressedStream, err := gzip.NewReader(gzipStream)
    
    	if err != nil {
    		return fmt.Errorf("could not create new targz reader: %v", err)
    	}
    
    	// create tar reader
    	tarReader := tar.NewReader(uncompressedStream)
    
    	for {
    		// read archive header
    		header, err := tarReader.Next()
    
    		if err == io.EOF {
    			break
    		}
    
    		if err != nil {
    			return fmt.Errorf("could not read next entry: %v", err)
    		}
    
    		destPath := filepath.Join(folder, header.Name)
    
    		switch header.Typeflag {
    		case tar.TypeDir:
    			// if a directory already exists skip its creation
    			if com.IsDir(destPath) {
    				continue
    			}
    
    			if err := os.Mkdir(destPath, 0755); err != nil {
    				return fmt.Errorf("could not create directory '%s': %v", destPath, err)
    			}
    		case tar.TypeReg:
    			// if a file already exists skip its creation
    			if com.IsFile(destPath) {
    				continue
    			}
    
    			outFile, err := os.Create(destPath)
    
    			if err != nil {
    				return fmt.Errorf("could not create file '%s': %v", destPath, err)
    			}
    
    			if _, err := io.Copy(outFile, tarReader); err != nil {
    				return fmt.Errorf("could not copy entry '%s': %v", destPath, err)
    			}
    
    			outFile.Close()
    		default:
    			return fmt.Errorf("uknown type: %s in %s", string(header.Typeflag), destPath)
    		}
    	}
    
    	return nil
    }
    
    func main() {
        err := ExtractTarGz("example.tar.gz", "/tmp")
    
        if err != nil {
            panic(err)
        }
    }

    An example of unpacking a tar.gz archive into the specified directory in Go.

  • Copy file in Go

    package main
    
    import (
        "io"
        "fmt"
        "os"
    )
    
    // copy file using os package
    func copyFileUsingOsPackage(src, dst string) error {
        bytesRead, err := os.ReadFile(src)
        if err != nil {
            return err
        }
    
        return os.WriteFile(dst, bytesRead, 0644)
    }
    
    // copy file using io package
    func copyFileUsingIoPackage(src, dst string) (int64, error) {
            source, err := os.Open(src)
            if err != nil {
                    return 0, err
            }
            defer source.Close()
    
            destination, err := os.Create(dst)
            if err != nil {
                    return 0, err
            }
            defer destination.Close()
            
            nBytes, err := io.Copy(destination, source)
            
            return nBytes, err
    }
    
    func main() {
        src := "/tmp/file-src.txt"
        dst := "/tmp/file-dst.txt"
    
        n, err := copyFileUsingIoPackage(src, dst)
    
        if err != nil {
            panic(err)
        }
    
        fmt.Printf("Copied %d bytes", n)
        fmt.Println()
    
        err = copyFileUsingOsPackage(src, dst)
    
        if err != nil {
            panic(err)
        }
    }

    This example shows how to copy a file in Golang.

  • Filename without extension in Go

    package main
    
    import (
        "fmt"
        "path/filepath"
        "strings"
    )
    
    func main() {
        filePath := "/tmp/file.ext"
    
        // get file name with extension
        fileName := filepath.Base(filePath)
    
        // get file extension
        fileExt := filepath.Ext(filePath)
    
        // truncate file name extension
        fileNameWithoutExt := strings.TrimSuffix(fileName, fileExt)
    
        fmt.Println("File name without extension: " + fileNameWithoutExt)
    }
    
    // $ go run main.go
    // File name without extension: file

    Here is an example of how to get filename without extension in go.

  • Base64 encoding and decoding in Go

    package main
    
    import (
    	b64 "encoding/base64"
    	"fmt"
    )
    
    func main() {
    	str := "text123321!?$*&()'-=@~"
    
    	// Encode using the standard encoder
    	strEnc := b64.StdEncoding.EncodeToString([]byte(str))
    	fmt.Println(strEnc)
    
    	strDec, err := b64.StdEncoding.DecodeString(strEnc)
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(string(strDec))
    	fmt.Println()
    
    	// Encode using a URL-compatible base64 format
    	strEnc = b64.URLEncoding.EncodeToString([]byte(str))
    	fmt.Println(strEnc)
    
    	strDec, err = b64.URLEncoding.DecodeString(strEnc)
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(string(strDec))
    }
    
    // $ go run main.go
    // dGV4dDEyMzMyMSE/JComKCknLT1Afg==
    // text123321!?$*&()'-=@~
    
    // dGV4dDEyMzMyMSE_JComKCknLT1Afg==
    // text123321!?$*&()'-=@~

    Here is an example of base64 encoding and decoding. Go supports both standard and URL-compatible base64.

  • Parse URL in Go

    package main
    
    import (
    	"fmt"
    	"net"
    	"net/url"
    )
    
    func main() {
    	s := "mysql://user:pass@host.com:3306/path?key=value#fragment"
    
    	u, err := url.Parse(s)
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println("Scheme: " + u.Scheme)
    
    	fmt.Println("Username: " + u.User.Username())
    	p, _ := u.User.Password()
    	fmt.Println("Password: " + p)
    
    	fmt.Println("Host with port: " + u.Host)
    
    	host, port, err := net.SplitHostPort(u.Host)
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println("Host: " + host)
    	fmt.Println("Port: " + port)
    
    	fmt.Println("Path: " + u.Path)
    	fmt.Println("Fragment: " + u.Fragment)
    
    	fmt.Println("Raw query: " + u.RawQuery)
    
    	m, err := url.ParseQuery(u.RawQuery)
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println("Value: " + m["key"][0])
    }
    
    // $ go run main.go 
    // Scheme: mysql
    // Username: user
    // Password: pass
    // Host with port: host.com:3306
    // Host: host.com
    // Port: 3306
    // Path: /path
    // Fragment: fragment
    // Raw query: key=value
    // Value: value

    Here is an example of how to parse URL, which includes a scheme, authentication info, host, port, path, query params, and query fragment.

  • Goroutines in Go

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func print(from string) {
    	for i := 0; i < 3; i++ {
    		fmt.Println(from, ":", i)
    	}
    }
    
    func main() {
    	// Synchronous function call
    	print("synchronous call")
    
    	// Asynchronous function call
    	// To run this function in a goroutine, use go f(s)
    	// This new goroutine will execute concurrently with the calling main goroutine
    	go print("asynchronous call")
    
    	// Goroutine can also be execute as an anonymous function
    	go func(msg string) {
    		fmt.Println(msg)
    	}("asynchronous anonymous call")
    
    	// Two previous function calls are now running asynchronously in separate goroutines
    	// Wait for them to finish
    	time.Sleep(time.Second)
    	fmt.Println("done")
    }
    
    // $ go run main.go
    // synchronous call : 0
    // synchronous call : 1
    // synchronous call : 2
    // asynchronous anonymous call
    // asynchronous call : 0
    // asynchronous call : 1
    // asynchronous call : 2
    // done

    Here is an example of goroutines in Golang.

  • Buffered and unbuffered channels in Go

    package main
    
    import "fmt"
    
    func main() {
        // Create unbuffered channel
    	unbufferedChannel := make(chan string)
    
    	go func() {
            // Send a value into a channel using the channel<- syntax
    		unbufferedChannel <- "unbuffered channel"
    	}()
    
        // The <-channel syntax receives a value from the channel
    	fmt.Println(<-unbufferedChannel)
    
        // Create buffered channel with size 2
    	bufferedChannel := make(chan string, 2)
    
        // Send a value to a buffered channel. The operation in non blocking
    	bufferedChannel <- "buffered"
    	bufferedChannel <- "channel"
    
    	fmt.Println(<-bufferedChannel)
    	fmt.Println(<-bufferedChannel)
    }
    
    // go run main.go 
    // unbuffered channel
    // buffered
    // channel

    Channels serve as pipes for communication between concurrent goroutines. They allow one goroutine to send values and another goroutine to receive those values. By default, sending and receiving operations block until both the sender and receiver are ready. This feature enabled us to wait for the "unbuffered channel" message at the end of our program without needing any additional synchronization mechanisms. Buffered channels can hold a limited number of values without requiring an immediate receiver.

  • Environment variables in Go

    package main
    
    import (
    	"fmt"
    	"os"
    	"strings"
    )
    
    func main() {
    	os.Setenv("FOO", "1")
    	fmt.Println("FOO:", os.Getenv("FOO"))
    	fmt.Println("BAR:", os.Getenv("BAR"))
    
    	fmt.Println("----------------------")
    
    	for _, env := range os.Environ() {
    		pair := strings.SplitN(env, "=", 2)
    		fmt.Println(pair[0])
    	}
    }
    
    // FOO: 1
    // BAR: 
    // ----------------------
    // HOSTNAME
    // PWD
    // HOME
    // LANG
    // SHLVL
    // PATH
    // _
    // FOO

    Here's an example how you can manage environment variables. To assign a value to a key, utilize os.Setenv. Retrieve a value by key using os.Getenv, which will yield an empty string if the key isn't found. Use os.Environ to list all key/value pairs, returned as a string slice formatted as KEY=value. You can split these strings using strings.SplitN to separate keys and values.

  • Example of recursion in golang

    package main
    
    import "fmt"
    
    func factorial(n int) int {
    	if n == 0 {
    		return 1
    	}
    
    	return n * factorial(n-1)
    }
    
    func main() {
    	fmt.Println(factorial(5))
    }
    
    // $ go run main.go 
    // 120

    Recursion in Go using the example of factorial calculation.

  • Example of closures in Golang

    package main
    
    import "fmt"
    
    // The function createCounter returns anonymous function defined within its body.
    // The returned function encapsulates the variable count, creating a closure.
    func createCounter() func() int {
    	count := 0
    
    	return func() int {
    		count++
    
    		return count
    	}
    }
    
    func main() {
        // We invoke createCounter, storing the result (a function) in counter variable.
        // This function captures and retains its own count value,
        // which updates with each subsequent invocation of createCounter.
    	counter := createCounter()
    
    	fmt.Println(counter())
    	fmt.Println(counter())
    	fmt.Println(counter())
    
    	newCounter := createCounter()
    	
        fmt.Println(newCounter())
    }
    
    // $ go run main.go 
    // 1
    // 2
    // 3
    // 1

    A simple example of using closures in Go.

  • Detect OS in Go

    package main
    
    import (
        "fmt"
        "runtime"
    )
    
    func main() {
        // The runtime.GOOS constant can be used to detect the OS at runtime,
        // since this constant is only set at runtime.
        os := runtime.GOOS
    
        switch os {
        case "windows":
            fmt.Println("Windows")
        case "darwin":
            fmt.Println("MacOS")
        case "linux":
            fmt.Println("Linux")
        default:
            fmt.Printf("%s.\n", os)
        }
    
        // The runtime.GOARCH constant can be used to determine the target architecture of a running program.
        fmt.Println(runtime.GOARCH)
    }
    
    // Output:
    // Linux
    // amd64

    GOOS constant to determine the operating system your Go program is running on. Here's an example of how to check the operating system in Go.

  • Create temporary file or directory in Go

    package main
    
    import (
        "fmt"
        "os"
        "path/filepath"
    )
    
    func checkErr(err error) {
        if err != nil {
            panic(err)
        }
    }
    
    func main() {
        // The simplest way to create a temporary file is to call os.CreateTemp.
        // It will create and open the file for reading and writing.
        // We used "" as the first argument, so os.CreateTemp will create a file in the default directory.
        tmpFile, err := os.CreateTemp("", "tmpfile")
        checkErr(err)
        defer os.Remove(tmpFile.Name())
    
        fmt.Println("Temp file name:", tmpFile.Name())
    
        // Write some data to the temporary file
        _, err = tmpFile.Write([]byte{1, 2, 3, 4, 5})
        checkErr(err)
    
        // If we intend to write a lot of temporary files, we may prefer to create a temporary directory.
        // The arguments to os.MkdirTemp are the same as for os.CreateTemp, but it returns the directory name rather than the opened file.
        dName, err := os.MkdirTemp("", "tmpdir")
        checkErr(err)
        defer os.RemoveAll(dName)
        
        fmt.Println("Temp directory name:", dName)
    
        fName := filepath.Join(dName, "testFile")
        err = os.WriteFile(fName, []byte{1, 2, 3, 4, 5}, 0666)
        checkErr(err)
        defer os.Remove(fName)
    }
    
    // Output:
    // Temp file name: /tmp/tmpfile3400905374
    // Temp directory name: /tmp/tmpdir2812568099

    During program execution, we often want to create data that is not needed after the program exits. Temporary files and directories are useful for this purpose because they do not pollute the file system over time.

  • Panic recovery in Go

    package main
    
    import "fmt"
    
    func main() {
        // Recover function must be called inside a deferred function.
        // When the enclosing function panics, defer is activated and the restore call inside it catches the panic.
        defer func() {
            if r := recover(); r != nil {
                fmt.Printf("recovered: %s\n", r)
            }
        }()
    
        panic("some fatal error")
        
        // This code won't run because of panic.
        // Basic operations stop during a panic and resume during a deferred close.
        fmt.Println("after panic")
    }

    Go allows you to recover from a panic with a built-in recover function. Recovery can prevent a panic from causing the program to abort and instead allow it to continue executing.

  • Writing files in Go

    package main
    
    import (
        "bufio"
        "fmt"
        "os"
    )
    
    func checkErr(err error) {
        if err != nil {
            panic(err)
        }
    }
    
    func main() {
        content := "Some content"
        // write a string (or just bytes) into a file
        err := os.WriteFile("/tmp/dfile1", []byte(content), 0644)
        checkErr(err)
    
        // open a file for writing
        file, err := os.Create("/tmp/dfile2")
        checkErr(err)
        // defer a Close immediately after opening a file
        defer file.Close()
    
        bytesCount, err := file.Write([]byte(content))
        checkErr(err)
        fmt.Printf("wrote %d bytes\n", bytesCount)
    
        bytesCount, err = file.WriteString("Some other content\n")
        checkErr(err)
        fmt.Printf("wrote %d bytes\n", bytesCount)
        // flush writes to a stable storage (file system for example)
        file.Sync()
    
        // bufio provides buffered writers
        writer := bufio.NewWriter(file)
        bytesCount, err = writer.WriteString("Some othe buffered content\n")
        checkErr(err)
        fmt.Printf("wrote %d bytes\n", bytesCount)
        // ensure all buffered operations have been applied to the underlying writer
        writer.Flush()
    }

    Here are examples of writing data to files using Go.