-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/slice abstractions #27
Draft
schonmann
wants to merge
5
commits into
feature/generics
Choose a base branch
from
feature/slice-abstractions
base: feature/generics
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 4 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
ef99aaa
Creating slice abstractions using generics
schonmann fc8dd34
Adding remaining function comments
schonmann 7172f2f
Fixing slice methods to return `Slice[T]`
schonmann d1e9053
Testing `Filter` method
schonmann 8ff59d7
Removing `main` func from slice module
schonmann File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package lib | ||
|
||
import "fmt" | ||
|
||
type Slice[T any] []T | ||
type Predicate[T any] func (iteratee T) bool | ||
|
||
// Filter returns slice items matching specified predicate | ||
func (slice Slice[T]) Filter(predicate Predicate[T]) Slice[T] { | ||
filtered := Slice[T]{} | ||
for _, v := range slice { | ||
if predicate == nil || predicate(v) { | ||
filtered = append(filtered, v) | ||
} | ||
} | ||
return filtered | ||
} | ||
|
||
// First returns the first item matching specified predicate | ||
func (slice Slice[T]) First(predicate Predicate[T]) *T { | ||
for i, v := range slice { | ||
if predicate == nil || predicate(v) { | ||
return &slice[i] | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// Last returns the last item matching specified predicate | ||
func (slice Slice[T]) Last(predicate Predicate[T]) *T { | ||
for i := len(slice)-1; i >= 0; i-- { | ||
if predicate == nil || predicate(slice[i]) { | ||
return &slice[i] | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// Any returns if any item matches the specified predicate | ||
func (slice Slice[T]) Any(predicate Predicate[T]) bool { | ||
for _, v := range slice { | ||
if predicate == nil || predicate(v) { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
// Every returns if every item matches the specified predicate | ||
func (slice Slice[T]) Every(predicate Predicate[T]) bool { | ||
for _, v := range slice { | ||
if !predicate(v) { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
// Copy returns a copy of the slice | ||
func (slice Slice[T]) Copy() Slice[T] { | ||
rSlice := make(Slice[T], len(slice)) | ||
copy(rSlice, slice) | ||
return rSlice | ||
} | ||
|
||
// Reverse returns the slice in a reversed order | ||
func (slice Slice[T]) Reverse() Slice[T] { | ||
rSlice := slice.Copy() | ||
for i, j := 0, len(rSlice)-1; i < j; i, j = i+1, j-1 { | ||
rSlice[i], rSlice[j] = rSlice[j], rSlice[i] | ||
} | ||
return rSlice | ||
} | ||
|
||
type User struct { | ||
Name string | ||
Tickets int | ||
} | ||
|
||
func main() { | ||
slice := Slice[User]{ | ||
{Name: "a", Tickets: 3}, | ||
{Name: "b", Tickets: 1}, | ||
{Name: "c", Tickets: 2}, | ||
} | ||
fmt.Printf("Users with >= 2 tickets: %v\n", slice.Filter(func (u User) bool{ | ||
return u.Tickets >= 2 | ||
})) | ||
fmt.Printf("First with <= 2 tickets: %v\n", slice.First(func (u User) bool{ | ||
return u.Tickets <= 2 | ||
})) | ||
fmt.Printf("Last with >= 3 tickets: %v\n", slice.Last(func (u User) bool{ | ||
return u.Tickets >= 3 | ||
})) | ||
fmt.Printf("Last with >= 10 tickets: %v\n", slice.Last(func (u User) bool{ | ||
return u.Tickets >= 10 | ||
})) | ||
fmt.Printf("Has any with name \"foo\": %v\n", slice.Any(func (u User) bool{ | ||
return u.Name == "foo" | ||
})) | ||
fmt.Printf("Every has > 0 tickets: %v\n", slice.Every(func (u User) bool{ | ||
return u.Tickets > 0 | ||
})) | ||
fmt.Printf("Slice address: %p / Slice copy address: %p\n", slice, slice.Copy()) | ||
fmt.Printf("Slice in reverse: %v\n", slice.Reverse()) | ||
fmt.Printf("Original Slice: %v\n", slice) | ||
} | ||
schonmann marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package lib | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
type TestUser struct { | ||
Name string | ||
Age int | ||
} | ||
|
||
func TestSliceFilter(t *testing.T) { | ||
type args struct { | ||
users Slice[TestUser] | ||
predicate Predicate[TestUser] | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want Slice[TestUser] | ||
}{ | ||
{ | ||
name: "should return [Jonah]", | ||
args: args{ | ||
users: Slice[TestUser]{ | ||
{Name: "Jonah", Age: 18}, | ||
{Name: "Camile", Age: 22}, | ||
}, | ||
predicate: func(u TestUser) bool { | ||
return u.Name == "Jonah" | ||
}, | ||
}, | ||
want: Slice[TestUser]{ | ||
{Name: "Jonah", Age: 18}, | ||
}, | ||
}, | ||
{ | ||
name: "should return []", | ||
args: args{ | ||
users: Slice[TestUser]{ | ||
{Name: "Jonah", Age: 18}, | ||
{Name: "Camile", Age: 22}, | ||
}, | ||
predicate: func(u TestUser) bool { | ||
return u.Name == "Math" | ||
}, | ||
}, | ||
want: Slice[TestUser]{}, | ||
}, | ||
{ | ||
name: "should return all if predicate is nil", | ||
args: args{ | ||
users: Slice[TestUser]{ | ||
{Name: "Jonah", Age: 18}, | ||
{Name: "Camile", Age: 22}, | ||
}, | ||
predicate: nil, | ||
}, | ||
want: Slice[TestUser]{ | ||
{Name: "Jonah", Age: 18}, | ||
{Name: "Camile", Age: 22}, | ||
}, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
if actual := tt.args.users.Filter(tt.args.predicate); !reflect.DeepEqual(tt.want, actual) { | ||
t.Fail() | ||
} | ||
}) | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think this type of params maybe better for utilization in code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you be more specific on the reasons why? I aggree that this could have less friction with legacy code, but at this point we should question what is indeed idiomatic in Golang. It seems quite reasonable that generic type abstractions like
Slice[T]
orMap[TK,TV]
would be a better choice for 1.18+ Golang code, as custom, reusable behaviour can be easily added to satistfy application needs.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think is better have less friction with legacy code, cuz the community probably will make something similar to this PR in the std lib, so we can make an agnostic function that we recive any slice is better for now