Login light
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/

// See page 161.

// Coloredpoint demonstrates struct embedding.
package main

import (
    "fmt"
    "math"
)

//!+decl
import "image/color"

type Point struct{ X, Y float64 }

type ColoredPoint struct {
    Point
    Color color.RGBA
}

//!-decl

func (p Point) Distance(q Point) float64 {
    dX := q.X - p.X
    dY := q.Y - p.Y
    return math.Sqrt(dX*dX + dY*dY)
}

func (p *Point) ScaleBy(factor float64) {
    p.X *= factor
    p.Y *= factor
}

func main() {
    //!+main
    red := color.RGBA{255, 0, 0, 255}
    blue := color.RGBA{0, 0, 255, 255}
    var p = ColoredPoint{Point{1, 1}, red}
    var q = ColoredPoint{Point{5, 4}, blue}
    fmt.Println(p.Distance(q.Point)) // "5"
    p.ScaleBy(2)
    q.ScaleBy(2)
    fmt.Println(p.Distance(q.Point)) // "10"
    //!-main
}

/*
//!+error
    p.Distance(q) // compile error: cannot use q (ColoredPoint) as Point
//!-error
*/

func init() {
    //!+methodexpr
    p := Point{1, 2}
    q := Point{4, 6}

    distance := Point.Distance   // method expression
    fmt.Println(distance(p, q))  // "5"
    fmt.Printf("%T\n", distance) // "func(Point, Point) float64"

    scale := (*Point).ScaleBy
    scale(&p, 2)
    fmt.Println(p)            // "{2 4}"
    fmt.Printf("%T\n", scale) // "func(*Point, float64)"
    //!-methodexpr
}

func init() {
    red := color.RGBA{255, 0, 0, 255}
    blue := color.RGBA{0, 0, 255, 255}

    //!+indirect
    type ColoredPoint struct {
        *Point
        Color color.RGBA
    }

    p := ColoredPoint{&Point{1, 1}, red}
    q := ColoredPoint{&Point{5, 4}, blue}
    fmt.Println(p.Distance(*q.Point)) // "5"
    q.Point = p.Point                 // p and q now share the same Point
    p.ScaleBy(2)
    fmt.Println(*p.Point, *q.Point) // "{2 2} {2 2}"
    //!-indirect
}