golang实现TypeScript风格模式匹配功能的插件库go-pattern-match的使用
Golang实现TypeScript风格模式匹配功能的插件库go-pattern-match的使用
什么是模式匹配?
模式匹配起源于ML、Haskell和Erlang等函数式编程语言。它提供了一种强大的技术,用于基于输入与模式的匹配来控制流程。
与使用条件语句和switch语句的命令式控制流相比,模式匹配能够实现更简洁和声明式的代码,特别是在处理复杂的条件逻辑时。它避免了冗长的样板代码,更好地传达了意图。
关键组件
Patterner
: 这是一个需要实现Match
函数的接口。任何实现此接口的类型都可以用作匹配器中的模式。Handler
: 这是一个返回泛型类型T
的函数类型。当找到匹配时调用此函数。Matcher
: 这是一个结构体,保存要匹配的值、指示是否找到匹配的标志以及找到匹配时要返回的响应。
基本使用方法
package main
import (
"fmt"
"github.com/phakornkiong/go-pattern-match/pattern"
)
func match(input []int) string {
return pattern.NewMatcher[string](input).
WithValues(
[]any{1, 2, 3, 4},
func() string { return "Nope" },
).
WithValues(
[]any{
pattern.Any(),
pattern.Not(36),
pattern.Union[int](99, 98),
255,
},
func() string { return "Its a match" },
).
Otherwise(func() string { return "Otherwise" })
}
func main() {
fmt.Println(match([]int{1, 2, 3, 4})) // "Nope"
fmt.Println(match([]int{25, 35, 99, 255})) // "Its a match"
fmt.Println(match([]int{1, 5, 6, 7})) // "Otherwise"
}
主要API方法
NewMatcher[T any, V any](input V) *Matcher[T, V]
创建一个新的Matcher实例。泛型T
和V
代表任何类型。
T
是处理函数在找到匹配时将返回的类型。
V
是将与模式匹配的输入值的类型。
.WithPattern(pattern Patterner, fn Handler[T]) *Matcher[T, V]
检查提供的模式是否匹配整个输入。如果找到匹配,则调用提供的Handler函数并返回响应T
。
.WithPatterns(patterns []Patterner, fn Handler[T]) *Matcher[T, V]
检查每个提供的模式是否匹配每个输入。如果找到匹配,则调用提供的Handler函数并返回响应T
。
.WithValue(value V, fn Handler[T]) *Matcher[T, V]
检查提供的值与整个输入之间是否存在深度相等。如果找到匹配,则调用提供的Handler函数并返回响应T
。
.WithValues(values any, fn Handler[T]) *Matcher[T, V]
如果模式作为模式提供,它将通过在每个值上调用Match
方法来检查任何提供的值是否匹配输入,否则将对每个值进行深度相等检查。如果找到匹配,则调用提供的Handler函数并返回响应T
。
.Otherwise(fn Handler[T]) *Matcher[T, V]
当没有找到输入的匹配时调用。它调用提供的Handler函数并返回响应T
。
常用模式示例
Any模式
func match(input int) string {
return pattern.NewMatcher[string](input).
WithValue(
2,
func() string { return "Nope" },
).
WithPattern(
pattern.Any(), // 总是匹配
func() string { return "Its a match" },
).
Otherwise(func() string { return "Nope" })
}
match(5) // "Its a match"
match(6) // "Its a match"
match(7) // "Its a match"
Not模式
func match(input int) string {
return pattern.NewMatcher[string](input).
WithValue(
2,
func() string { return "2" },
).
WithPattern(
pattern.Not(3), // 如果不是3则匹配
func() string { return "Its a match" },
).
Otherwise(func() string { return "Otherwise" })
}
match(3) // "Otherwise"
match(6) // "Its a match"
match(7) // "Its a match"
When模式
func match(input int) string {
return pattern.NewMatcher[string](input).
WithValue(
2,
func() string { return "2" },
).
WithPattern(
// 如果输入大于100则匹配
pattern.When[int](func(i int) bool { return i > 100 }),
func() string { return "Its a match" },
).
Otherwise(func() string { return "Otherwise" })
}
match(2) // "2"
match(99) // "Otherwise"
match(100) // "Its a match"
match(105) // "Its a match"
Union模式
func FoodSorterWithPattern(input string) (output string) {
output = pattern.NewMatcher[string](input).
WithPattern(
pattern.Union("apple", "strawberry", "orange"),
func() string { return "fruit" },
).
WithPattern(
pattern.Union("carrot", "pok-choy", "cabbage"),
func() string { return "vegetable" },
).
Otherwise(func() string { return "unknown" })
return output
}
FoodSorterWithPattern("apple") // "fruit"
FoodSorterWithPattern("orange") // "fruit"
FoodSorterWithPattern("carrot") // "vegetable"
FoodSorterWithPattern("candy") // "unknown"
String模式
func match(input string) string {
pattern1 := pattern.String().
StartsWith("hello").
EndsWith("world").
MaxLength(11)
pattern2 := pattern.String().
Contains("dni").
Regex(regexp.MustCompile("night$"))
pattern3 := pattern.String().
MinLength(3)
pattern4 := pattern.String()
return pattern.NewMatcher[string](input).
WithPattern(
pattern1,
func() string { return "pattern 1" },
).
WithPattern(
pattern2,
func() string { return "pattern 2" },
).
WithPattern(
pattern3,
func() string { return "pattern 3" },
).
WithPattern(
pattern4,
func() string { return "pattern 4" },
).
Otherwise(func() string { return "This is impossible" })
}
match("hello world") // "pattern 1"
match("goodnight") // "pattern 2"
match("abc") // "pattern 3"
match("ab") // "pattern 4"
match("") // "pattern 4"
Slice模式
func match(input []int) string {
pattern1 := pattern.Slice[int]().
Head(1).
Tail(100)
subPattern2 := pattern.Int().Between(75, 100)
pattern2 := pattern.Slice[int]().
Contains(25).
Contains(50).
ContainsPattern(subPattern2)
subHeadPattern3 := pattern.Int().Gt(1000)
subTailattern3 := pattern.Int().Gt(2500)
pattern3 := pattern.Slice[int]().
HeadPattern(subHeadPattern3).
TailPattern(subTailattern3)
return pattern.NewMatcher[string](input).
WithPattern(
pattern1,
func() string { return "pattern 1" },
).
WithPattern(
pattern2,
func() string { return "pattern 2" },
).
WithPattern(
pattern3,
func() string { return "pattern 3" },
).
Otherwise(func() string { return "No pattern matched" })
}
match([]int{1, 2, 3, 100}) // "pattern 1"
match([]int{2, 25, 85, 50}) // "pattern 2"
match([]int{1001, 25, 3, 25001}) // "pattern 3"
总结
go-pattern-match库为Golang提供了类似TypeScript风格的强大模式匹配功能,使得复杂的条件逻辑可以以更声明式和简洁的方式表达。通过使用各种内置模式和方法,开发者可以构建灵活且易于维护的模式匹配逻辑。
更多关于golang实现TypeScript风格模式匹配功能的插件库go-pattern-match的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang实现TypeScript风格模式匹配功能的插件库go-pattern-match的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
go-pattern-match: Golang实现TypeScript风格模式匹配
go-pattern-match是一个受TypeScript/Elm/Haskell启发的Golang模式匹配库,它提供了类似函数式编程语言的模式匹配能力。下面我将详细介绍它的使用方法和示例代码。
安装
go get github.com/alexpantyukhin/go-pattern-match
基本用法
1. 简单值匹配
import "github.com/alexpantyukhin/go-pattern-match"
result := match.Match(42).
When(42, func() interface{} {
return "the answer to life, the universe and everything"
}).
When(100, func() interface{} {
return "one hundred"
}).
Otherwise(func() interface{} {
return "something else"
})
fmt.Println(result) // 输出: the answer to life, the universe and everything
2. 类型匹配
func process(input interface{}) string {
return match.Match(input).
When(match.String, func() interface{} {
return "got a string: " + input.(string)
}).
When(match.Int, func() interface{} {
return fmt.Sprintf("got an int: %d", input.(int))
}).
Otherwise(func() interface{} {
return "unknown type"
}).(string)
}
fmt.Println(process("hello")) // 输出: got a string: hello
fmt.Println(process(123)) // 输出: got an int: 123
fmt.Println(process(1.23)) // 输出: unknown type
3. 结构体匹配
type User struct {
Name string
Age int
}
user := User{Name: "Alice", Age: 30}
result := match.Match(user).
When(User{Name: "Alice"}, func() interface{} {
return "Hello Alice!"
}).
When(User{Age: match.Gt(18)}, func() interface{} {
return "Adult user"
}).
Otherwise(func() interface{} {
return "Unknown user"
})
fmt.Println(result) // 输出: Hello Alice!
4. 切片/数组匹配
func describeList(list []int) string {
return match.Match(list).
When([]int{}, func() interface{} {
return "empty list"
}).
When([]int{match.Any}, func() interface{} {
return "list with one element"
}).
When([]int{match.Any, match.Any}, func() interface{} {
return "list with two elements"
}).
Otherwise(func() interface{} {
return "list with many elements"
}).(string)
}
fmt.Println(describeList([]int{})) // empty list
fmt.Println(describeList([]int{1})) // list with one element
fmt.Println(describeList([]int{1, 2})) // list with two elements
fmt.Println(describeList([]int{1,2,3})) // list with many elements
高级特性
1. 谓词匹配
result := match.Match(15).
When(match.Gt(10), func() interface{} {
return "greater than 10"
}).
When(match.Lt(5), func() interface{} {
return "less than 5"
}).
Otherwise(func() interface{} {
return "between 5 and 10"
})
fmt.Println(result) // 输出: greater than 10
2. 自定义匹配器
func evenNumber() match.Matcher {
return func(value interface{}) bool {
if num, ok := value.(int); ok {
return num%2 == 0
}
return false
}
}
result := match.Match(4).
When(evenNumber(), func() interface{} {
return "even number"
}).
Otherwise(func() interface{} {
return "odd number"
})
fmt.Println(result) // 输出: even number
3. 解构匹配
type Point struct {
X, Y int
}
p := Point{X: 1, Y: 2}
result := match.Match(p).
When(Point{X: 0, Y: 0}, func() interface{} {
return "origin"
}).
When(Point{X: match.Any, Y: 0}, func() interface{} {
return "on x-axis"
}).
When(Point{X: 0, Y: match.Any}, func() interface{} {
return "on y-axis"
}).
Otherwise(func() interface{} {
return fmt.Sprintf("at (%d, %d)", p.X, p.Y)
})
fmt.Println(result) // 输出: at (1, 2)
与TypeScript模式匹配的对比
虽然Golang没有TypeScript那样原生的模式匹配语法,但go-pattern-match提供了类似的表达能力:
- 值匹配:类似于TypeScript的
switch
或if-else
链 - 类型保护:类似于TypeScript的类型守卫
- 解构模式:类似于TypeScript的对象解构匹配
- 谓词匹配:类似于TypeScript的自定义类型谓词
注意事项
- 由于Golang是静态类型语言,模式匹配不如TypeScript灵活
- 性能上会比原生条件语句稍慢,但大多数场景差异可以忽略
- 错误处理需要结合Golang的error机制
总结
go-pattern-match为Golang带来了接近TypeScript风格的模式匹配能力,虽然不如原生支持那么简洁,但在需要复杂条件分支时能显著提高代码可读性。它特别适合处理多种类型或复杂结构的条件分支场景。
对于更简单的条件判断,传统的if-else
或switch
语句可能仍然是更好的选择,但在需要更强大的模式匹配能力时,go-pattern-match是一个很好的选择。