# README
Parametric Constraints
Your interface definitions, which can later be used as constraints, can accept type parameters as well.
// The store interface represents a store that sells products.
// It takes a type parameter P that represents the type of products the store sells.
type store[P product] interface {
Sell(P)
}
type product interface {
Price() float64
Name() string
}
type book struct {
title string
author string
price float64
}
func (b book) Price() float64 {
return b.price
}
func (b book) Name() string {
return fmt.Sprintf("%s by %s", b.title, b.author)
}
type toy struct {
name string
price float64
}
func (t toy) Price() float64 {
return t.price
}
func (t toy) Name() string {
return t.name
}
// The bookStore struct represents a store that sells books.
type bookStore struct {
booksSold []book
}
// Sell adds a book to the bookStore's inventory.
func (bs *bookStore) Sell(b book) {
bs.booksSold = append(bs.booksSold, b)
}
// The toyStore struct represents a store that sells toys.
type toyStore struct {
toysSold []toy
}
// Sell adds a toy to the toyStore's inventory.
func (ts *toyStore) Sell(t toy) {
ts.toysSold = append(ts.toysSold, t)
}
// sellProducts takes a store and a slice of products and sells
// each product one by one.
func sellProducts[P product](s store[P], products []P) {
for _, p := range products {
s.Sell(p)
}
}
func main() {
bs := bookStore{
booksSold: []book{},
}
// By passing in "book" as a type parameter, we can use the sellProducts function to sell books in a bookStore
sellProducts[book](&bs, []book{
{
title: "The Hobbit",
author: "J.R.R. Tolkien",
price: 10.0,
},
{
title: "The Lord of the Rings",
author: "J.R.R. Tolkien",
price: 20.0,
},
})
fmt.Println(bs.booksSold)
// We can then do the same for toys
ts := toyStore{
toysSold: []toy{},
}
sellProducts[toy](&ts, []toy{
{
name: "Lego",
price: 10.0,
},
{
name: "Barbie",
price: 20.0,
},
})
fmt.Println(ts.toysSold)
}
Assignment
The chief architect at Mailio has decided she wants to implement billing with generics. Specifically, she wants us to create a new biller
interface. A biller
is an interface that can be used to charge a customer
, and it can also report its name
.
There are two kinds of billers:
userBiller
(cheaper)orgBiller
(more expensive)
A customer
is either a user
or an org
. A user
will be billed with a userBiller
and an org
with an orgBiller
.
Create the new biller
interface. It should have 2 methods:
Charge
Name
The good news is that the architect already wrote the userBiller
and orgBiller
types for us that fulfill this new biller
interface. Use the definitions of those types and their methods to figure out how to write the biller
interface definition starting on line 7.