Take the following bit of code.
func main() {
	fooMessage := "Hello, world!"
	fmt.Printf("How immutable are you, '%s'?\n", fooMessage)
	// How immutable are you, 'Hello, world!'?
}
What we've been told is that fooMessage, by being assigned, now points to an immutable structure. But what does that mean? Well, when we try to mutate it, we first get blocked by the compiler.
func main() {
	fooMessage := "Hello, world!"
	fooMessage[0] = 'a' // cannot assign to fooMessage[0] (neither addressable nor a map index expression)
	fmt.Printf("How immutable are you, '%s'?\n", fooMessage)
}
Can't let that deter us though, we know that go is "c-like", so let's take a look at some c?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char** args)
{
  char fooMessage[14];
  strncpy(fooMessage, "Hello, world!", sizeof(fooMessage));
  fooMessage[0] = 'C';
  printf("How immutable are you, '%s'?\n", fooMessage);
  // How immutable are you, 'Cello, world!'?
  return 0;
} 
Success! Let's port this over, but first we're going to need to take a little detour through go's unsafe package to get to the underlying pointer and not let the compiler stop us.
p := unsafe.StringData("Hello, world!")
fmt.Printf("%p\n", p)
// 0x102f418cf
Putting it all together:
func main() {
	fooMessage := "Hello, world!"
	p := unsafe.StringData(fooMessage)
	fmt.Printf("%p\n", p)
	*p = 'C'
	// unexpected fault address 0x102dcd1a8
	// fatal error: fault
	// [signal SIGBUS: bus error code=0x1 addr=0x102dcd1a8 pc=0x102d93960]
	fmt.Printf("How immutable are you, '%s'?", fooMessage)
}
Oh, dear. Not quite a success, but why? Well, to explain, let's take another look at our c code. The astute might have already noticed that it's not actually a straight port. The c code uses an array of char, where the go code uses a string literal; what happens when we resolve the discrepancy?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char** args)
{
  char *fooMessage = "Hello, world!";
  *fooMessage = 'C';
  // Bus error: 10
  printf("How immutable are you, '%s'?\n", fooMessage);
  return 0;
}
Hey! That's the same message! But why? We can see a hint if we change what we're taking the address of from something the compiler knows at compile time, to something that is built up at runtime:
func main() {
	fooMessage := "Hello, world!"
	fmt.Printf("%p\n", unsafe.StringData(fooMessage))
	// 0x102b119fc
	f2 := fmt.Sprintf("%s", fooMessage)
	fmt.Printf("%p\n", unsafe.StringData(f2))
	// 0x776914ed4480
}
Notice the shorter address on the first block. The string is actually stored in a different section of memory. That explains the SIGBUS we saw before, it has something to do with the memory that we dereferenced. There's something else that's kinda neat here, when run over and over again there's a noticeable pattern:

~/Projects/immutable-strings
$ go build -o mgo main.go
~/Projects/immutable-strings
$ ./mgo
0x1029fe2a8
0x2c7456438060
~/Projects/immutable-strings
$ ./mgo
0x102bea2a8
0x56511b740060
~/Projects/immutable-strings
$ ./mgo 
0x102cbe2a8
0x991481a4020

Let's take a peek inside that binary and see what's sitting around 2a8...
87654321  0011 2233 4455 6677 8899 aabb ccdd eeff
000a2290: 746c 7373 6563 706d 6c6b 656d 746c 7375  tlssecpmlkemtlsu
000a22a0: 6e73 6166 6565 6b6d 4865 6c6c 6f2c 2077  nsafeekmHello, w
000a22b0: 6f72 6c64 2133 3831 3436 3937 3236 3536  orld!38146972656
Sure enough, it's our string! What's going on here is that the memory is being mapped into a section of the binary where the data is marked in a read-only boundary:
00000150: 5f5f 726f 6461 7461 0000 0000 0000 0000  __rodata........
00000160: 5f5f 5445 5854 0000 0000 0000 0000 0000  __TEXT..........
When the application attempts to modify that memory at runtime, the hardware reports back that something illegal is happening and kills the application. Which makes the obvious question come up... what happens when we try to modify that memory when it's been copied out of the boundary?
func main() {
	fooMessage := "Hello, world!"
	fmt.Printf("%p\n", unsafe.StringData(fooMessage))
	// 0x102b119fc
	f2 := fmt.Sprintf("%s", fooMessage)
	ptr := unsafe.StringData(f2)
	fmt.Printf("%p\n", ptr)
	// 0x776914ed4480

	*ptr = 'C'

	fmt.Printf("How immutable are you, '%s'?", f2)
	// How immutable are you, 'Cello, world!'?
}
Not so immutable after all 🎻