
Welcome to GOtchas in Go, a ten-part saga where I take on Golang and document the process. This is post 1 of 10. If you've been traumatized by loosely typed JavaScript or overly typed TypeScript, welcome. Go sits somewhere else entirely.
In this first post, we'll go over:
- Variable declaration
- Printing messages
- Writing functions
- Structs and how they compare to TypeScript types
- Interfaces in Go vs TypeScript
- How interfaces work with functions
- Declaring a type that satisfies an interface
Let's GO.
Variables ๐งช
Go makes you declare things. It's not happy guessing.
package main
import "fmt"
func main() {
var name string = "Carneiro"
age := 30 // short-hand, Go figures the type
fmt.Println(name, age)
}var is explicit. := is lazy. Choose your fighter. But only inside functions. Outside, you have to use var.
var planet = "Earth"Go will infer the type unless you need to be specific. But you can do this:
var id int = 42Functions โ๏ธ
Functions look like this:
func greet(name string) string {
return "Hello, " + name
}Multiple returns? Go says yes:
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}No exceptions. You return errors manually. Which is weird until it isn't.
Structs vs TypeScript Types ๐งฑ
type User = {
name: string;
age: number;
};Here's the Go version:
type User struct {
Name string
Age int
}Note: Fields starting with uppercase letters are exported (public). Lowercase is private. Go does not have public or private keywords. It just yells at you softly.
You instantiate a struct like this:
user := User{Name: "Alice", Age: 25}Or like this:
var user User
user.Name = "Bob"
user.Age = 32You want to print it?
fmt.Printf("%+v\n", user) // shows field names and valuesInterfaces in Go vs TypeScript ๐ค
In TypeScript:
interface Greeter {
greet(): string;
}
class Person implements Greeter {
greet() {
return "Hello";
}
}Go looks like this:
type Greeter interface {
Greet() string
}
type Person struct {
Name string
}
func (p Person) Greet() string {
return "Hello, I am " + p.Name
}Two things to notice:
- Go interfaces are implicit.
Persondoesn't say "I implement Greeter." If it has aGreet() stringmethod, it is aGreeter. - You don't use classes. Structs plus methods = close enough.
This works:
func sayHello(g Greeter) {
fmt.Println(g.Greet())
}
func main() {
p := Person{Name: "Ada"}
sayHello(p) // no explicit implementation needed
}That's it. You build your types and Go just checks if they match the interface. No formal contracts. Just vibes and signatures.
Functions as Interfaces ๐ญ
You can define interfaces that expect function-like behavior. For example:
type MathOp interface {
Operate(a, b int) int
}And then you build types that satisfy it:
type Adder struct{}
func (Adder) Operate(a, b int) int {
return a + b
}Or use it more flexibly with functions as fields:
type Operation struct {
Apply func(int, int) int
}
func main() {
op := Operation{
Apply: func(a, b int) int {
return a * b
},
}
fmt.Println(op.Apply(2, 3)) // 6
}But no, you can't assign a raw function to an interface unless it's declared as a type. You'll get bit by the type checker.
Summary ๐
You've seen:
- How variables work, and when Go wants a
var - The syntax for defining and using functions
- Structs and how they replace TypeScript types
- Interfaces that don't need to be declared, just satisfied
- How structs and interfaces interact
- And how functions sneak into interface land
Go doesn't try to be clever. It just wants you to be explicit. Unless you're implementing interfaces. Then it's all implied.
What's Next? ๐
Post 2 will cover:
- Error handling (with more details)
- Maps
- Pointers (yeah, that kind of pointer)
Stay tuned. GOtchas in Go continues soon.