{"id":29117201,"url":"https://github.com/PhakornKiong/go-pattern-match","last_synced_at":"2025-06-29T11:14:18.135Z","repository":{"id":187923796,"uuid":"674750516","full_name":"PhakornKiong/go-pattern-match","owner":"PhakornKiong","description":"Pattern Matching library for go","archived":false,"fork":false,"pushed_at":"2023-08-26T10:18:46.000Z","size":85,"stargazers_count":93,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-13T17:49:08.213Z","etag":null,"topics":["branching","conditions","go","golang","matching","pattern","pattern-matching"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PhakornKiong.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-04T17:17:26.000Z","updated_at":"2024-10-26T18:00:37.000Z","dependencies_parsed_at":"2023-08-18T22:56:39.263Z","dependency_job_id":"fcd5a300-dbd9-48e3-b6f9-b99d41c2d5f8","html_url":"https://github.com/PhakornKiong/go-pattern-match","commit_stats":null,"previous_names":["phakornkiong/go-pattern","phakornkiong/go-pattern-match"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/PhakornKiong/go-pattern-match","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhakornKiong%2Fgo-pattern-match","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhakornKiong%2Fgo-pattern-match/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhakornKiong%2Fgo-pattern-match/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhakornKiong%2Fgo-pattern-match/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PhakornKiong","download_url":"https://codeload.github.com/PhakornKiong/go-pattern-match/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PhakornKiong%2Fgo-pattern-match/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262581514,"owners_count":23331925,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["branching","conditions","go","golang","matching","pattern","pattern-matching"],"created_at":"2025-06-29T11:14:14.184Z","updated_at":"2025-06-29T11:14:18.107Z","avatar_url":"https://github.com/PhakornKiong.png","language":"Go","funding_links":[],"categories":["Utilities","公用事业公司"],"sub_categories":["Utility/Miscellaneous","实用程序/Miscellaneous"],"readme":"# Go-Pattern-Match\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/PhakornKiong/go-pattern-match/blob/master/LICENSE)\n[![Test](https://github.com/PhakornKiong/go-pattern-match/actions/workflows/test.yml/badge.svg)](https://github.com/PhakornKiong/go-pattern-match/actions/workflows/test.yml)\n[![codecov](https://codecov.io/gh/PhakornKiong/go-pattern-match/branch/master/graph/badge.svg?token=IL7G963OAF)](https://codecov.io/gh/PhakornKiong/go-pattern-match)\n[![Go Report Card](https://goreportcard.com/badge/github.com/phakornkiong/go-pattern-match)](https://goreportcard.com/report/github.com/phakornkiong/go-pattern-match)\n[![GoDoc](https://godoc.org/phakornkiong/go-pattern-match?status.svg)](https://godoc.org/github.com/phakornkiong/go-pattern-match)\n[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go) \n\nPattern Matching library for Go\n\n```go\npackage main\n\nimport (\n  \"fmt\"\n\n  \"github.com/phakornkiong/go-pattern-match/pattern\"\n)\n\nfunc match(input []int) string {\n  return pattern.NewMatcher[string](input).\n    WithValues(\n      []any{1, 2, 3, 4},\n      func() string { return \"Nope\" },\n    ).\n    WithValues(\n      []any{\n        pattern.Any(),\n        pattern.Not(36),\n        pattern.Union[int](99, 98),\n        255,\n      },\n      func() string { return \"Its a match\" },\n    ).\n    Otherwise(func() string { return \"Otherwise\" })\n}\n\nfunc main() {\n  fmt.Println(match([]int{1, 2, 3, 4}))      // \"Nope\"\n  fmt.Println(match([]int{25, 35, 99, 255})) // \"Its a match\"\n  fmt.Println(match([]int{1, 5, 6, 7}))      // \"Otherwise\"\n}\n```\n\n## Why Pattern Matching?\n\nPattern matching originated in functional programming languages like ML, Haskell, and Erlang. It provides a powerful technique for control flow based on matching inputs against patterns.\n\nCompared to imperative control flow using conditionals and switch statements, pattern matching enables more concise and declarative code, especially when handling complex conditional logic. It avoids verbose boilerplate code and better conveys intent.\n\n## Key Components\n\n- `Patterner`: This is an interface that requires the implementation of a `Match` function. Any type that implements this interface can be used as a pattern in the matcher.\n\n- `Handler`: This is a function type that returns a generic type `T`. This function is called when a match is found.\n\n- `Matcher`: This is a struct that holds the value to be matched, a flag indicating if a match has been found, and the response to be returned when a match is found.\n\n## Documentation\n\n### `NewMatcher[T any, V any](input V) *Matcher[T, V]`\n\nThis function creates a new Matcher instance. The generics `T` and `V` represent any types.\n\n`T` is the type that the handler function will return when a match is found.\n\n`V` is the type of the input value that will be matched against the patterns.\n\n### `.WithPattern(pattern Patterner, fn Handler[T]) *Matcher[T, V]`\n\nIt checks if the provided pattern matches the entire input. If a match is found, it calls the provided Handler function and return the response `T`.\n\n### `.WithPatterns(patterns []Patterner, fn Handler[T]) *Matcher[T, V]`\n\nIt checks each of the provided patterns against \u003cb\u003eeach of the input\u003c/b\u003e. If a match is found, it calls the provided Handler function and return the response `T`.\n\n### `.WithValue(value V, fn Handler[T]) *Matcher[T, V]`\n\nIt checks for deep equality between the provided value and the entire input. If a match is found, it calls the provided Handler function and return the response `T`.\n\n### `.WithValues(values any, fn Handler[T]) *Matcher[T, V]`\n\nIf a `Patterner` is provided as the pattern, it will check if any of the provided values matches the input by calling the `Match` method on each value, else it will do a deep equality check on each value.\nIf a match is found, it calls the provided Handler function and return the response `T`.\n\nThis enables more flexible pattern match where the provided values can be a `patterner` or just `actual value`.\n\nFor example, now you can use many of the built-in patterns like `Union`, `Any`, `Not`. See the [Patterns](#patterns) section for more details.\n\n```go\nfunc match(input []int) string {\n  return pattern.NewMatcher[string](input).\n    WithValues(\n      []any{1, 2, 3, 4},\n      func() string { return \"Nope\" },\n    ).\n    WithValues(\n      []any{\n        pattern.Any(),\n        pattern.Not(36),\n        pattern.Union[int](99, 98),\n        255,\n      },\n      func() string { return \"Its a match\" },\n    ).\n    Otherwise(func() string { return \"Otherwise\" })\n}\n\nmatch([]int{1, 2, 3, 4}) // \"Nope\"\nmatch([]int{25, 35, 99, 255}) // \"Its a match\"\nmatch([]int{1, 5, 6, 7}) // \"Otherwise\"\n```\n\n### `.Otherwise(fn Handler[T]) *Matcher[T, V]`\n\nIt is called when no match is found for the input. It calls the provided Handler function and return the response `T`.\n\n## [Patterns](#patterns)\n\nPatterns provide a way to declaratively match values. In general, they all implements the `Patterner` interface which requires a `Match(any) bool` method.\n\nSome common patterns included are:\n\n- [Any Pattern](#any-pattern)\n- [Not Pattern](#not-pattern)\n- [NotPattern Pattern](#notpattern-pattern)\n- [When Pattern](#when-pattern)\n- [Union Pattern](#union-pattern)\n- [UnionPattern Pattern](#unionpattern-pattern)\n- [IntersectionPattern Pattern](#intersectionpattern-pattern)\n- [String Pattern](#string-pattern)\n- [Int Pattern](#int-pattern)\n- [Slice Pattern](#slice-pattern)\n- [Map Pattern](#map-pattern)\n- [Struct Pattern](#struct-pattern)\n\nCurrently you can use [When Pattern](#when-pattern) to do custom matching logic for these pattern.\n\n### [Any Pattern](#any-pattern)\n\n`pattern.Any()` returns a `Patterner` that matches any value.\n\n```go\nfunc match(input int) string {\n  return pattern.NewMatcher[string](input).\n    WithValue(\n      2,\n      func() string { return \"Nope\" },\n    ).\n    WithPattern(\n      pattern.Any(), // Always matches\n      func() string { return \"Its a match\" },\n    ).\n    Otherwise(func() string { return \"Nope\" })\n}\n\nmatch(5) // \"Its a match\"\nmatch(6) // \"Its a match\"\nmatch(7) // \"Its a match\"\n```\n\n### [Not Pattern](#not-pattern)\n\n`pattern.Not(input)` returns a `Patterner` that matches any value other than the input by comparing using deep equality.\n\n```go\nfunc match(input int) string {\n  return pattern.NewMatcher[string](input).\n    WithValue(\n      2,\n      func() string { return \"2\" },\n    ).\n    WithPattern(\n      pattern.Not(3), // Always matches if not 3\n      func() string { return \"Its a match\" },\n    ).\n    Otherwise(func() string { return \"Otherwise\" })\n}\n\nmatch(3) // \"Otherwise\"\nmatch(6) // \"Its a match\"\nmatch(7) // \"Its a match\"\n```\n\n### [NotPattern Pattern](#notpattern-pattern)\n\nSimilar to `Not` pattern, but accepts only a `Patterner` instead of a value. Used mainly to get inverse of a pattern.\n\n```go\nfunc match(input int) string {\n  intPattern := pattern.Int().Between(25, 35)\n  return pattern.NewMatcher[string](input).\n    WithValue(\n      2,\n      func() string { return \"2\" },\n    ).\n    WithPattern(\n      // Always matches if not in between 25 \u0026 35\n      pattern.NotPattern(intPattern),\n      func() string { return \"Its a match\" },\n    ).\n    Otherwise(func() string { return \"Otherwise\" })\n}\n\nmatch(2) // \"2\"\nmatch(30) // \"Otherwise\"\nmatch(36) // \"Its a match\"\nmatch(24) // \"Its a match\"\n```\n\n### [When Pattern](#when-pattern)\n\n`When` pattern accepts a predicate, which is a function that takes a value and returns a boolean. This pattern matches when the predicate function returns true for the input value.\n\n```go\nfunc match(input int) string {\n  return pattern.NewMatcher[string](input).\n    WithValue(\n      2,\n      func() string { return \"2\" },\n    ).\n    WithPattern(\n      // match if input larger than 100\n      pattern.When[int](func(i int) bool { return i \u003e 100 }),\n      func() string { return \"Its a match\" },\n    ).\n    Otherwise(func() string { return \"Otherwise\" })\n}\n\nmatch(2) // \"2\"\nmatch(99) // \"Otherwise\"\nmatch(100) // \"Its a match\"\nmatch(105) // \"Its a match\"\n```\n\n### [Union Pattern](#union-pattern)\n\n`Union` pattern matches if the input equals any of the provided values by using deep equality check.\n\n```go\nfunc FoodSorterWithPattern(input string) (output string) {\n  output = pattern.NewMatcher[string](input).\n    WithPattern(\n      pattern.Union(\"apple\", \"strawberry\", \"orange\"),\n      func() string { return \"fruit\" },\n    ).\n    WithPattern(\n      pattern.Union(\"carrot\", \"pok-choy\", \"cabbage\"),\n      func() string { return \"vegetable\" },\n    ).\n    Otherwise(func() string { return \"unknown\" })\n\n  return output\n}\n\nFoodSorterWithPattern(\"apple\")  // \"fruit\"\nFoodSorterWithPattern(\"orange\") // \"fruit\"\nFoodSorterWithPattern(\"carrot\") // \"vegetable\"\nFoodSorterWithPattern(\"candy\")  // \"unknown\"\n```\n\n### [UnionPattern Pattern](#unionpattern-pattern)\n\nSimilar to [Union pattern](#union-pattern) but accepts only `Patterner` instead of values. Useful for extending patterning capabilities.\n\n### [IntersectionPattern Pattern](#intersectionpattern-pattern)\n\n`IntersectionPattern` accepts multiple patterns and matches if the input matches all of them. Useful for extending patterning capabilities.\n\n### [String Pattern](#string-pattern)\n\n`String` pattern matches string values. It provides additional methods to match on string contents:\n\n#### `StartsWith(value string) stringPattern`\n\nChainable method for matching strings starting with the provided value.\n\n#### `EndsWith(value string) stringPattern`\n\nChainable method for matching strings ending with the provided value.\n\n#### `Contains(value string) stringPattern`\n\nChainable method for matching strings containing the provided value.\n\n#### `Regex(value string) stringPattern`\n\nChainable method for matching strings according to the provided regular expression.\n\n#### `MinLength(value int) stringPattern`\n\nChainable method for matching strings with a minimum length of the provided value.\n\n#### `MaxLength(value int) stringPattern`\n\nChainable method for matching strings with a maximum length of the provided value.\n\nHere is an example of how to use these methods:\n\n```go\nfunc match(input string) string {\n  pattern1 := pattern.String().\n    StartsWith(\"hello\").\n    EndsWith(\"world\").\n    MaxLength(11)\n\n  pattern2 := pattern.String().\n    Contains(\"dni\").\n    Regex(regexp.MustCompile(\"night$\"))\n\n  pattern3 := pattern.String().\n    MinLength(3)\n\n  pattern4 := pattern.String()\n\n  return pattern.NewMatcher[string](input).\n    WithPattern(\n      pattern1,\n      func() string { return \"pattern 1\" },\n    ).\n    WithPattern(\n      pattern2,\n      func() string { return \"pattern 2\" },\n    ).\n    WithPattern(\n      pattern3,\n      func() string { return \"pattern 3\" },\n    ).\n    WithPattern(\n      pattern4,\n      func() string { return \"pattern 4\" },\n    ).\n    Otherwise(func() string { return \"This is impossible\" })\n}\n\nmatch(\"hello world\") // \"pattern 1\"\nmatch(\"goodnight\")   // \"pattern 2\"\nmatch(\"abc\")         // \"pattern 3\"\nmatch(\"ab\")          // \"pattern 4\"\nmatch(\"\")            // \"pattern 4\"\n\n```\n\n### [Int Pattern](#int-pattern)\n\nTo be documented\n\n### [Slice Pattern](#slice-pattern)\n\n`Slice` pattern matches slice values. It provides additional methods to match on slice contents:\n\n#### `Head(v V) slicePattern[V]`\n\nChainable method for the first element of the input slice to equal the provided value.\n\n#### `HeadPattern(p Patterner) slicePattern[V]`\n\nChained method for the first element of the input slice to match the provided pattern. It calls the underlying `Patterner`'s `Match` method.\n\n#### `Tail(v V) slicePattern[V]`\n\nChainable method for the last element of the input slice to equal the provided value.\n\n#### `TailPattern(p Patterner) slicePattern[V]`\n\nChained method for the last element of the input slice to match the provided pattern. It calls the underlying `Patterner`'s `Match` method.\n\n#### `Contains(v V) slicePattern[V]`\n\nChainable method for the input slice to contain the provided value. Can be used multiple times to check for multiple values.\n\n#### `Contains(p Patterner) slicePattern[V]`\n\nChainable method for the input slice to contain element that matches the provided pattern. It calls the underlying `Patterner`'s `Match` method. Can be used multiple times to check for multiple patterns.\n\n```go\nfunc match(input []int) string {\n  pattern1 := pattern.Slice[int]().\n    Head(1).\n    Tail(100)\n\n  subPattern2 := pattern.Int().Between(75, 100)\n\n  pattern2 := pattern.Slice[int]().\n    Contains(25).\n    Contains(50).\n    ContainsPattern(subPattern2)\n\n  subHeadPattern3 := pattern.Int().Gt(1000)\n  subTailattern3 := pattern.Int().Gt(2500)\n  pattern3 := pattern.Slice[int]().\n    HeadPattern(subHeadPattern3).\n    TailPattern(subTailattern3)\n\n  return pattern.NewMatcher[string](input).\n    WithPattern(\n      pattern1,\n      func() string { return \"pattern 1\" },\n    ).\n    WithPattern(\n      pattern2,\n      func() string { return \"pattern 2\" },\n    ).\n    WithPattern(\n      pattern3,\n      func() string { return \"pattern 3\" },\n    ).\n    Otherwise(func() string { return \"No pattern matched\" })\n}\n\nmatch([]int{1, 2, 3, 100})       // \"pattern 1\"\nmatch([]int{2, 25, 85, 50})      // \"pattern 2\"\nmatch([]int{1001, 25, 3, 25001}) // \"pattern 3\"\n```\n\n### [Map Pattern](#map-pattern)\n\nTo be documented\n\n### [Struct Pattern](#struct-pattern)\n\nTo be documented\n\n## Examples\n\nYou can find more examples and usage scenarios [here](https://github.com/PhakornKiong/go-pattern-match/tree/master/example). Following are some of notable use case:\n\n- [shippingStrategy](https://github.com/PhakornKiong/go-pattern-match/blob/master/example/shippingStrategy/main.go)\n- [fxStrategy](https://github.com/PhakornKiong/go-pattern-match/blob/master/example/fxstrategy/main.go)\n- [switchUnion](https://github.com/PhakornKiong/go-pattern-match/blob/master/example/switchunion/main.go)\n\nThese files a demonstrate its common use case. You may also refer to the test file for more information\n\n## Inspiration\n\nThis library is heavily inspired by [ts-pattern](https://github.com/gvergnaud/ts-pattern) which provides powerful pattern matching capabilities for TypeScript. The goal is to provide a similar experience in Go.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPhakornKiong%2Fgo-pattern-match","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPhakornKiong%2Fgo-pattern-match","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPhakornKiong%2Fgo-pattern-match/lists"}