How to start with strings in Golang

Reading Time: 3 minutes

Today we will see the working of strings in golang.

We all know that immutable data is simple but the program must allocate memory for data change.But sometimes there is no extra memory for that allocation or when you dont want to burden the garbage collector.

Whats interesting about Go is that it has its own data type string.At bottom it is still a sequence of byte but with some additional features.

  • Its immutable
  • It has fixed length
  • Length is also given at the same time.

Unlike the C lang the Golang memory layout starts from the last part first i.e the Len which is the length.

How to use StringHeader ?

Lets start with using the string .

To convert from one Go type to another we use the unsafe package :

import (
        "unsafe"
)s := "rishivant"
header := (*StringHeader)(unsafe.Pointer(&s))

Now in the above code unsafe.Pointer is an untyped pointer.In the above case we are coverting a *string into an unsafe.Pointer into a *StringHeader. Now we know how string works in Golang.

Lets see the woking of len function of Golang.

func strLen(q string) int {
        header := (*StringHeader)(unsafe.Pointer(&q)
        return header.Len
}

In the above code we can see how the len function works in Golang.

Do you want to change or set the length of the string ?

You can acheive this by altering the Len field of string header.

s := "hello"
header := (*StringHeader)(unsafe.Pointer(&s))
header.Len = 100   // cast the header back to 'string' and print it
fmt.Print(*(*string)(unsafe.Pointer(header)))

/* on stdout:
helloint16int32int64panicslicestartuint8write (MB)
 Value addr= code= ctxt: curg= list= m->p= p->m=
*/

Using the above the memory space can be expanded for including other members in the same part.

The above code points to a StringHeader that has an unsafe.Pointer which points to the strings sequence of bytes.

How to build a [ ]byte from pointer in Golang?

The below code shows it

type SliceHeader struct {
        Data unsafe.Pointer
        Len int
        Cap int
}

The above code shows how a slice looks like.Its the same as StringHeader except it has a Cap(capacity) field.

How to build a SliceHeader from the fields of StringHeader in Golang?

Lets take an example of converting string to [ ]byte.

func strToBytes(s string) []byte {
    header := (*StringHeader)(unsafe.Pointer(&s))
    bytesHeader := &SliceHeader{
        Data: header.Data,
        Len: header.Len,
        Cap: header.Len,
    }
    return *(*[]byte)(unsafe.Pointer(bytesHeader))
}fmt.Print(strToBytes("rishi")) 

// [104 101 108 108 111]

In the above example we can see the use of pointer stringheader .The unsafe.Pointer is being used in the header. The return value is giving the standard output by converting string to bytes.

Both the string and [ ]byte headers use the same data pointer so they share same memory.

NOTE: String in Go is immutable not [ ]byte.

Accessing individual bytes of a string.

As now we know that string is a slice of bytes , we can access each bytes of string.

Here is a small example of how to use string and its manipulation in real world.

package main
  
import "fmt"
  
// Main function
func main() {
  
    // Creating and initializing a string
    r := "Welcome"
  
    // Accessing the bytes of the given string
    for c := 0; c < len(r); c++ {
  
        fmt.Printf("\nCharacter = %c Bytes = %v", r, r)
    }
}

output:

Character = W Bytes = 87
Character = e Bytes = 101
Character = l Bytes = 108
Character = c Bytes = 99
Character = o Bytes = 111
Character = m Bytes = 109
Character = e Bytes = 101

Conclusion

So with reference to the above article you can work with string at anytime.

The blog has made it simpler and easier to work with strings in Go lang.

Reference

https://go.dev/src/reflect/value.go?ref=faun

https://pkg.go.dev/strings

Written by 

Rishivant is a enthusiastic devops learner at Knoldus. He believes in going 1% up everyday and showcases his learning in his work.

Leave a Reply