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