C#
GO

C# to Go

10 lessons

Progress0%
1Introduction2Type System3Classes to Structs4Interfaces5Error Handling6Async to Goroutines7Generics8LINQ to Slices9Testing10Packages and Modules
All Mirror Courses
C#
GO
Interfaces
MirrorLesson 4 of 10
Lesson 4

Interfaces

Interfaces

Introduction

In this lesson, you'll learn about interfaces in Go. Coming from C#, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.

Mirror Card
C#
From C#:

In C#, you're familiar with interfaces.

GO
In Go:

Go has its own approach to interfaces, which we'll explore step by step.

The Go Way

Let's see how Go handles this concept. Here's a typical example:

GO
Go Example
package main

import "fmt"

type Animal interface {
    Speak() string
}

type Dog struct{}
type Cat struct{}

// No explicit "implements" — just implement the methods
func (d Dog) Speak() string { return "Woof!" }
func (c Cat) Speak() string { return "Meow!" }

func main() {
    var a Animal = Dog{}
    fmt.Println(a.Speak())
}

Comparing to C#

Here's how you might have written similar code in C#:

C#
C# (What you know)
interface IAnimal {
    string Speak();
}

class Dog : IAnimal {
    public string Speak() => "Woof!";
}

class Cat : IAnimal {
    public string Speak() => "Meow!";
}

IAnimal a = new Dog();
Console.WriteLine(a.Speak());
Mirror Card
C#
From C#:

You may be used to different syntax or behavior.

GO
In Go:

Go interfaces are satisfied implicitly — no 'class Dog : IAnimal' declaration needed

Mirror Card
C#
From C#:

You may be used to different syntax or behavior.

GO
In Go:

If a type has all the methods, it automatically implements the interface

Mirror Card
C#
From C#:

You may be used to different syntax or behavior.

GO
In Go:

This is called structural typing (duck typing at compile time)

Mirror Card
C#
From C#:

You may be used to different syntax or behavior.

GO
In Go:

Small interfaces are idiomatic in Go — often just one method

Mirror Card
C#
From C#:

You may be used to different syntax or behavior.

GO
In Go:

The empty interface (interface{} or any) accepts any value — like C# object

Step-by-Step Breakdown

1. Implicit Implementation

In C# you explicitly declare which interface a class implements. In Go you just implement the methods — the compiler figures out the rest.

C#
C#
interface IShape {
    double Area();
}
class Circle : IShape {  // explicit
    public double Area() => Math.PI * r * r;
}
GO
Go
type Shape interface {
    Area() float64
}

type Circle struct{ Radius float64 }

// No ": Shape" anywhere — just implement the method
func (c Circle) Area() float64 {
    return 3.14159 * c.Radius * c.Radius
}

// Circle now satisfies Shape automatically
Rule of Thumb
Implicit interfaces decouple the interface definition from the implementation — you can satisfy third-party interfaces without modifying the original package.

2. Small, Focused Interfaces

Go encourages tiny interfaces. The standard library's io.Reader and io.Writer each have exactly one method. Compare to ISP in SOLID.

C#
C#
interface ILogger {
    void LogInfo(string msg);
    void LogWarning(string msg);
    void LogError(string msg);
}
GO
Go
// Go idiom: small interfaces
type Writer interface {
    Write(p []byte) (n int, err error)
}

type Reader interface {
    Read(p []byte) (n int, err error)
}

// Compose when needed
type ReadWriter interface {
    Reader
    Writer
}

3. Interface Variables and Type Assertions

An interface variable holds both the concrete value and its type. Use type assertions to retrieve the concrete type — like C# 'as' operator.

C#
C#
IAnimal a = new Dog();
if (a is Dog dog) {
    Console.WriteLine("It's a dog: " + dog.Name);
}
GO
Go
var a Animal = Dog{Name: "Rex"}

// Type assertion (panics if wrong type)
dog := a.(Dog)

// Safe assertion (like C# 'as')
if dog, ok := a.(Dog); ok {
    fmt.Println("It's a dog:", dog.Name)
}
Common Pitfall
a.(Dog) panics at runtime if a is not a Dog. Always use the two-value form 'v, ok := a.(T)' unless you are certain of the type.

4. Empty Interface and any

The empty interface interface{} has no methods, so every type satisfies it. Go 1.18 added 'any' as an alias — use any in modern code.

C#
C#
object anything = 42;
anything = "now a string";
// Must cast to use: (string)anything
GO
Go
var anything any = 42
anything = "now a string"

// Type switch to handle multiple types
switch v := anything.(type) {
case int:
    fmt.Println("int:", v)
case string:
    fmt.Println("string:", v)
default:
    fmt.Println("unknown type")
}
Rule of Thumb
Avoid any/interface{} when possible — use typed interfaces or generics (Go 1.18+). any defeats type safety.

Common Mistakes

When coming from C#, developers often make these mistakes:

  • Go interfaces are satisfied implicitly — no 'class Dog : IAnimal' declaration needed
  • If a type has all the methods, it automatically implements the interface
  • This is called structural typing (duck typing at compile time)
Common Pitfall
Don't assume Go works exactly like C#. While the concepts may be similar, the syntax and behavior can differ significantly.

Key Takeaways

  • Go interfaces are satisfied implicitly — just implement the methods
  • Prefer small, single-method interfaces (io.Reader pattern)
  • Use the two-value type assertion 'v, ok := i.(T)' for safe type checks
  • Use 'any' (alias for interface{}) only when truly needed
Rule of Thumb
The best way to learn is by doing. Try rewriting some of your C# code in Go to practice these concepts.
PreviousNext