types4.goΒΆ

// types4.go

package main

import (
    "fmt"
)

type Point struct {
    x, y float64
}

// The method set of an interface is a the set of methods listed in it.
type Rectangler interface {
    width() float64
    height() float64
    upperLeft() Point
} // Rectangler

//////////////////////////////////////////////////////////////////

// In the following methods, the parameter r is of interface type Rectangler,
// which means any object that implements Rectangler could be passed to it. A
// type T implements the Rectangler interface is the methods set of T is a
// superset of the method set of Rectangle. The functions can only use methods
// in the method set of r, i.e. only methods listed in Rectangler.

func print(r Rectangler) {
    fmt.Printf("<corner=(%v, %v), w=%v, h=%v>",
        r.upperLeft().x, r.upperLeft().y, r.width(), r.height())
}

func println(r Rectangler) {
    print(r)
    fmt.Println()
}

func area(r Rectangler) float64 {
    return r.width() * r.height()
}

func perimeter(r Rectangler) float64 {
    return 2 * (r.width() * r.height())
}

//////////////////////////////////////////////////////////////////

type Rect1 struct {
    uLeft  Point
    lRight Point
} // Rect1

func makeRect1(x, y, width, height float64) Rect1 {
    return Rect1{Point{x, y}, Point{x + width, y + height}}
}

// The method set of Rect1 is all the methods with Rect1 as a receiever, i.e.
// width, height, and upperLeft. The method set of *Rect1 is all the methods
// with *Rect1 or Rect1 as the receiver. There are no methods with *Rect1 as
// the receiver, so the method set of *Rect1 is the same as the method set for
// Rect1.

func (r Rect1) width() float64 {
    return r.lRight.x - r.uLeft.x
}

func (r Rect1) height() float64 {
    return r.lRight.y - r.uLeft.y
}

func (r Rect1) upperLeft() Point {
    return r.uLeft
}

//////////////////////////////////////////////////////////////////

type Rect2 struct {
    uLeft Point
    w, h  float64
} // Rect2

func makeRect2(x, y, width, height float64) Rect2 {
    return Rect2{Point{x, y}, width, height}
}

func (r Rect2) width() float64 {
    return r.w
}

func (r Rect2) height() float64 {
    return r.h
}

func (r Rect2) upperLeft() Point {
    return Point{r.uLeft.x + r.w, r.uLeft.y + r.h}
}

//////////////////////////////////////////////////////////////////

func main() {
    a := makeRect1(0, 0, 10, 5)
    b := makeRect2(0, 0, 2, 2)

    println(a)
    fmt.Printf("area=%v, perim=%v\n", area(a), perimeter(a))
    println(b)
    fmt.Printf("area=%v, perim=%v\n", area(b), perimeter(b))
} // main