Tolti esempi prototipo
parent
c80b23c93d
commit
a11a034355
@ -1,60 +0,0 @@
|
|||||||
package genericmethods_test
|
|
||||||
|
|
||||||
type Cons[L, R any] struct {
|
|
||||||
Left L
|
|
||||||
Right L
|
|
||||||
}
|
|
||||||
|
|
||||||
// interface cast type check
|
|
||||||
func _[T any]() LiftLower[BoxT, T] { return &Box[T]{} }
|
|
||||||
|
|
||||||
type BoxT struct{}
|
|
||||||
type Box[T any] struct {
|
|
||||||
Content T
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Box[T]) Lift() V[BoxT, T] {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
func (c *Box[T]) Lower(v V[BoxT, T]) {
|
|
||||||
*c = v.(Box[T])
|
|
||||||
}
|
|
||||||
|
|
||||||
// interface cast type check
|
|
||||||
func _[T any]() LiftLower[ChestT, T] { return &Chest[T]{} }
|
|
||||||
|
|
||||||
type ChestT struct{}
|
|
||||||
type Chest[T any] struct {
|
|
||||||
Treasure T
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Chest[T]) Lift() V[ChestT, T] {
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
func (c *Chest[T]) Lower(v V[ChestT, T]) {
|
|
||||||
*c = v.(Chest[T])
|
|
||||||
}
|
|
||||||
|
|
||||||
type LiftLower[F ~struct{}, T any] interface {
|
|
||||||
Lift() V[F, T]
|
|
||||||
Lower(v V[F, T])
|
|
||||||
}
|
|
||||||
|
|
||||||
func BoxToChest[T any](b Box[T]) Chest[T] {
|
|
||||||
return Chest[T]{b.Content}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BoxToChestLifted[T any](b V[BoxT, T]) V[ChestT, T] {
|
|
||||||
var bb Box[T]
|
|
||||||
bb.Lower(b)
|
|
||||||
return Chest[T]{bb.Content}.Lift()
|
|
||||||
}
|
|
||||||
|
|
||||||
type V[F ~struct{}, T any] any
|
|
||||||
|
|
||||||
type ConsF[F, T, R any] struct{}
|
|
||||||
|
|
||||||
func _() {
|
|
||||||
// l1 := Cons[Box[int], Box[string]]{}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,134 +0,0 @@
|
|||||||
package genericmethods_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Validator interface {
|
|
||||||
Validate() error
|
|
||||||
}
|
|
||||||
|
|
||||||
type FooRequest struct {
|
|
||||||
A int `json:"a"`
|
|
||||||
B string `json:"b"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (foo FooRequest) Validate() error {
|
|
||||||
if foo.A < 0 {
|
|
||||||
return fmt.Errorf(`parameter "a" cannot be lesser than zero`)
|
|
||||||
}
|
|
||||||
if !strings.HasPrefix(foo.B, "baz-") {
|
|
||||||
return fmt.Errorf(`parameter "b" has wrong prefix`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecodeAndValidateJSON_Generic[T Validator](r *http.Request) (T, error) {
|
|
||||||
var value T
|
|
||||||
err := json.NewDecoder(r.Body).Decode(&value)
|
|
||||||
if err != nil {
|
|
||||||
var zero T
|
|
||||||
return zero, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := value.Validate(); err != nil {
|
|
||||||
var zero T
|
|
||||||
return zero, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return value, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecodeAndValidateJSON_Generic(t *testing.T) {
|
|
||||||
m := http.NewServeMux()
|
|
||||||
m.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
foo, err := DecodeAndValidateJSON_Generic[FooRequest](r)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
json.NewEncoder(w).Encode(foo)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecodeAndValidateJSON_Interface(r *http.Request, target *Validator) error {
|
|
||||||
err := json.NewDecoder(r.Body).Decode(target)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := (*target).Validate(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecodeAndValidateJSON_Interface(t *testing.T) {
|
|
||||||
m := http.NewServeMux()
|
|
||||||
m.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
var foo Validator = FooRequest{}
|
|
||||||
if err := DecodeAndValidateJSON_Interface(r, &foo); err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
json.NewEncoder(w).Encode(foo)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type WithPrimaryKey interface {
|
|
||||||
PrimaryKeyPtr() *string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Ref[T WithPrimaryKey] string
|
|
||||||
|
|
||||||
type Table[T WithPrimaryKey] struct {
|
|
||||||
Name string
|
|
||||||
PkColumn string
|
|
||||||
}
|
|
||||||
|
|
||||||
func IdToRef[T WithPrimaryKey](table Table[T], id string) (Ref[T], error) {
|
|
||||||
if !strings.HasPrefix(id, table.Name+":") {
|
|
||||||
var zero Ref[T]
|
|
||||||
return zero, fmt.Errorf(`invalid reference %v for table %v`, id, table)
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ref[T](id), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Read[T WithPrimaryKey](db *sql.DB, table Table[T], ref Ref[T]) (*T, error) {
|
|
||||||
result := db.QueryRow(
|
|
||||||
fmt.Sprintf(
|
|
||||||
`SELECT * FROM %s WHERE %s = ?`,
|
|
||||||
table.Name, table.PkColumn,
|
|
||||||
),
|
|
||||||
string(ref),
|
|
||||||
)
|
|
||||||
|
|
||||||
var value T
|
|
||||||
if err := result.Scan(&value); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &value, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
Username string
|
|
||||||
FirstName string
|
|
||||||
LastName string
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ WithPrimaryKey = &User{}
|
|
||||||
|
|
||||||
func (u *User) PrimaryKeyPtr() *string {
|
|
||||||
return &u.Username
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
package genericmethods_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"golang.org/x/exp/constraints"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Min[T constraints.Ordered](x, y T) T {
|
|
||||||
if x < y {
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
return y
|
|
||||||
}
|
|
||||||
|
|
||||||
type Liter int
|
|
||||||
|
|
||||||
func TestInt(t *testing.T) {
|
|
||||||
{
|
|
||||||
var a, b int = 1, 2
|
|
||||||
Min(a, b)
|
|
||||||
}
|
|
||||||
{
|
|
||||||
var a, b float64 = 3.14, 2.71
|
|
||||||
Min(a, b)
|
|
||||||
}
|
|
||||||
{
|
|
||||||
var a, b Liter = 1, 2
|
|
||||||
Min(a, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
package genericmethods_test
|
|
||||||
|
|
||||||
type Stack[T any] []T
|
|
||||||
|
|
||||||
func (s *Stack[T]) Push(value T) {
|
|
||||||
*s = append(*s, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Stack[T]) Peek() T {
|
|
||||||
return s[len(s)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Stack[T]) Len() int {
|
|
||||||
return len(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Stack[T]) Pop() (T, bool) {
|
|
||||||
items := *s
|
|
||||||
|
|
||||||
if len(items) == 0 {
|
|
||||||
var zero T
|
|
||||||
return zero, false
|
|
||||||
}
|
|
||||||
|
|
||||||
newStack, poppedValue := items[:len(items)-1], items[len(items)-1]
|
|
||||||
*s = newStack
|
|
||||||
|
|
||||||
return poppedValue, true
|
|
||||||
}
|
|
||||||
@ -1,99 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
)
|
|
||||||
|
|
||||||
//
|
|
||||||
// Database
|
|
||||||
//
|
|
||||||
|
|
||||||
type QueryResult interface {
|
|
||||||
Scan(v any) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type Database interface {
|
|
||||||
Get(query string, values ...any) QueryResult
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Library
|
|
||||||
//
|
|
||||||
|
|
||||||
// DatabaseTable represents a typed database table with
|
|
||||||
type DatabaseTable[T any] struct {
|
|
||||||
Table string
|
|
||||||
IdKey string
|
|
||||||
GetIdPtr func(entry T) *string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t DatabaseTable[T]) RefForId(id string) DatabaseRef[T] {
|
|
||||||
return DatabaseRef[T]{id}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t DatabaseTable[T]) RefForValue(v T) DatabaseRef[T] {
|
|
||||||
return t.RefForId(*t.GetIdPtr(v))
|
|
||||||
}
|
|
||||||
|
|
||||||
type DatabaseRef[T any] struct{ Id string }
|
|
||||||
|
|
||||||
func DatabaseRead[T any](db Database, table DatabaseTable[T], ref DatabaseRef[T]) (*T, error) {
|
|
||||||
query := fmt.Sprintf(`select * from %s where %s = ?`, table.Table, table.IdKey)
|
|
||||||
|
|
||||||
result := db.Get(query, ref.Id)
|
|
||||||
|
|
||||||
var value T
|
|
||||||
if err := result.Scan(&value); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &value, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DatabaseWrite creates a new entry in the db using the provided id in the value, this returns a typed ref to the db entry
|
|
||||||
func DatabaseWrite[T any](db Database, table DatabaseTable[T], value *T) (DatabaseRef[T], error) {
|
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// DatabaseCreate creates a new entry in the db retrieving the new generated id and returning it as a typed ref
|
|
||||||
func DatabaseCreate[T any](db Database, table DatabaseTable[T], value *T) (DatabaseRef[T], error) {
|
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Client code
|
|
||||||
//
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
Username string
|
|
||||||
FirstName string
|
|
||||||
LastName string
|
|
||||||
}
|
|
||||||
|
|
||||||
var UsersTable = DatabaseTable[User]{
|
|
||||||
Table: "users",
|
|
||||||
IdKey: "username",
|
|
||||||
GetIdPtr: func(u User) *string {
|
|
||||||
return &u.Username
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func _(db Database) error {
|
|
||||||
u1 := &User{"j.smith", "John", "Smith"}
|
|
||||||
log.Println(u1)
|
|
||||||
|
|
||||||
ref1, err := DatabaseWrite(db, UsersTable, u1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
u2, err := DatabaseRead(db, UsersTable, ref1)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Println(u2)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
// type Option[T] = Some(T) | None
|
|
||||||
|
|
||||||
type Option[T any] interface {
|
|
||||||
Match(
|
|
||||||
caseSome func(value T),
|
|
||||||
caseNone func(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Some[T any] struct{ Value T }
|
|
||||||
|
|
||||||
func (v Some[T]) Match(caseSome func(value T), caseNone func()) {
|
|
||||||
caseSome(v.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
type None[T any] struct{}
|
|
||||||
|
|
||||||
func (v None[T]) Match(caseSome func(value T), caseNone func()) {
|
|
||||||
caseNone()
|
|
||||||
}
|
|
||||||
|
|
||||||
// type Either[A, B] = Left A | Right B
|
|
||||||
|
|
||||||
type Either[A, B any] interface {
|
|
||||||
Match(
|
|
||||||
caseLeft func(value A),
|
|
||||||
caseRight func(value B),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Left[A, B any] struct{ Value A }
|
|
||||||
|
|
||||||
func (v Left[A, B]) Match(
|
|
||||||
caseLeft func(value A),
|
|
||||||
caseRight func(value B),
|
|
||||||
) {
|
|
||||||
caseLeft(v.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Right[A, B any] struct{ Value B }
|
|
||||||
|
|
||||||
func (v Right[A, B]) Match(
|
|
||||||
caseLeft func(value A),
|
|
||||||
caseRight func(value B),
|
|
||||||
) {
|
|
||||||
caseRight(v.Value)
|
|
||||||
}
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
type Expr[T any] interface{}
|
|
||||||
|
|
||||||
func Match() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
type numExpr struct {
|
|
||||||
value int
|
|
||||||
}
|
|
||||||
|
|
||||||
func Num(value int) Expr[int] {
|
|
||||||
return &numExpr{value}
|
|
||||||
}
|
|
||||||
|
|
||||||
type sumExpr struct {
|
|
||||||
lhs, rhs Expr[int]
|
|
||||||
}
|
|
||||||
|
|
||||||
func Sum(lhs, rhs Expr[int]) Expr[int] {
|
|
||||||
return &sumExpr{lhs, rhs}
|
|
||||||
}
|
|
||||||
|
|
||||||
type leqExpr struct {
|
|
||||||
lhs, rhs Expr[int]
|
|
||||||
}
|
|
||||||
|
|
||||||
func Leq(lhs, rhs Expr[int]) Expr[bool] {
|
|
||||||
return &leqExpr{lhs, rhs}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ifExpr[R any] struct {
|
|
||||||
cond Expr[bool]
|
|
||||||
ifTrue Expr[R]
|
|
||||||
ifFalse Expr[R]
|
|
||||||
}
|
|
||||||
|
|
||||||
func If[R any](cond Expr[bool], ifTrue Expr[R], ifFalse Expr[R]) Expr[R] {
|
|
||||||
return &ifExpr[R]{cond, ifTrue, ifFalse}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
package example5_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func WriteSingleWithInterface(w io.Writer, data byte) {
|
|
||||||
w.Write([]byte{data})
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:noinline
|
|
||||||
func WriteSingleWithInterfaceNoInline(w io.Writer, data byte) {
|
|
||||||
w.Write([]byte{data})
|
|
||||||
}
|
|
||||||
|
|
||||||
func WriteSingleWithGeneric[T io.Writer](w T, data byte) {
|
|
||||||
w.Write([]byte{data})
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:noinline
|
|
||||||
func WriteSingleWithGenericNoInline[T io.Writer](w T, data byte) {
|
|
||||||
w.Write([]byte{data})
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test1(t *testing.T) {
|
|
||||||
t.Log(`Ok!`)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkInterface(b *testing.B) {
|
|
||||||
d := &bytes.Buffer{}
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
WriteSingleWithInterface(d, 42)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkInterfaceNoInline(b *testing.B) {
|
|
||||||
d := &bytes.Buffer{}
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
WriteSingleWithInterfaceNoInline(d, 42)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkGeneric(b *testing.B) {
|
|
||||||
d := &bytes.Buffer{}
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
WriteSingleWithGeneric(d, 42)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkGenericNoInline(b *testing.B) {
|
|
||||||
d := &bytes.Buffer{}
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
WriteSingleWithGenericNoInline(d, 42)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue