Interfaces
Define and implement interfaces for polymorphism in Go
#interfaces #polymorphism #methods #types
Interfaces
Interfaces define behavior through method signatures in Go.
Basic Interface
package main
import "fmt"
type Shape interface {
Area() float64
}
type Rectangle struct {
width, height float64
}
func (r Rectangle) Area() float64 {
return r.width * r.height
}
func main() {
var s Shape
s = Rectangle{width: 10, height: 5}
fmt.Println("Area:", s.Area()) // 50
}
Multiple Implementations
type Circle struct {
radius float64
}
func (c Circle) Area() float64 {
return 3.14159 * c.radius * c.radius
}
func printArea(s Shape) {
fmt.Printf("Area: %.2f\n", s.Area())
}
func main() {
rect := Rectangle{10, 5}
circle := Circle{7}
printArea(rect) // Area: 50.00
printArea(circle) // Area: 153.94
}
Interface with Multiple Methods
type Geometry interface {
Area() float64
Perimeter() float64
}
type Rectangle struct {
width, height float64
}
func (r Rectangle) Area() float64 {
return r.width * r.height
}
func (r Rectangle) Perimeter() float64 {
return 2*r.width + 2*r.height
}
func measure(g Geometry) {
fmt.Println("Area:", g.Area())
fmt.Println("Perimeter:", g.Perimeter())
}
Empty Interface
func describe(i interface{}) {
fmt.Printf("Type: %T, Value: %v\n", i, i)
}
func main() {
describe(42) // Type: int, Value: 42
describe("hello") // Type: string, Value: hello
describe(true) // Type: bool, Value: true
describe([]int{1, 2}) // Type: []int, Value: [1 2]
}
Type Assertions
func main() {
var i interface{} = "hello"
// Type assertion
s := i.(string)
fmt.Println(s) // hello
// Type assertion with check
s, ok := i.(string)
if ok {
fmt.Println("String:", s)
}
// This would panic without check
// f := i.(float64)
f, ok := i.(float64)
fmt.Println("Float:", f, "OK:", ok) // Float: 0 OK: false
}
Type Switch
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Integer: %d\n", v)
case string:
fmt.Printf("String: %s\n", v)
case bool:
fmt.Printf("Boolean: %t\n", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}
func main() {
do(21) // Integer: 21
do("hello") // String: hello
do(true) // Boolean: true
do(3.14) // Unknown type: float64
}
Interface Composition
type Reader interface {
Read() string
}
type Writer interface {
Write(s string)
}
// Composed interface
type ReadWriter interface {
Reader
Writer
}
type File struct {
content string
}
func (f *File) Read() string {
return f.content
}
func (f *File) Write(s string) {
f.content = s
}
func main() {
var rw ReadWriter = &File{}
rw.Write("Hello, Go!")
fmt.Println(rw.Read()) // Hello, Go!
}
Stringer Interface
import "fmt"
type Person struct {
Name string
Age int
}
// Implement fmt.Stringer interface
func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}
func main() {
p := Person{"Alice", 30}
fmt.Println(p) // Alice (30 years old)
}
Error Interface
type MyError struct {
Message string
Code int
}
func (e MyError) Error() string {
return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}
func doSomething() error {
return MyError{"Something went wrong", 500}
}
func main() {
err := doSomething()
if err != null {
fmt.Println(err) // Error 500: Something went wrong
}
}
Interface Values
type I interface {
M()
}
type T struct {
S string
}
func (t *T) M() {
if t == nil {
fmt.Println("<nil>")
return
}
fmt.Println(t.S)
}
func main() {
var i I
// nil interface
// i.M() // Would panic
var t *T
i = t
i.M() // <nil> (interface holds nil value)
i = &T{"hello"}
i.M() // hello
}
Practical Example: Logger Interface
type Logger interface {
Log(message string)
}
type ConsoleLogger struct{}
func (c ConsoleLogger) Log(message string) {
fmt.Println("[CONSOLE]", message)
}
type FileLogger struct {
filename string
}
func (f FileLogger) Log(message string) {
fmt.Printf("[FILE:%s] %s\n", f.filename, message)
}
func process(logger Logger) {
logger.Log("Processing started")
// Do work...
logger.Log("Processing completed")
}
func main() {
process(ConsoleLogger{})
process(FileLogger{"app.log"})
}
Discover another handy tool from EditPDF.pro