diff --git a/modular/README.md b/modular/README.md
new file mode 100644
index 0000000..92c6c17
--- /dev/null
+++ b/modular/README.md
@@ -0,0 +1,73 @@
+# Modular
+
+[](https://pkg.go.dev/github.com/kercylan98/minotaur)
+
+
+暂无介绍...
+
+
+## 目录导航
+列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
+
+展开 / 折叠目录导航
+
+
+> 包级函数定义
+
+|函数名称|描述
+|:--|:--
+|[Run](#Run)|运行模块化应用程序
+|[RegisterServices](#RegisterServices)|注册服务
+
+
+> 类型定义
+
+|类型|名称|描述
+|:--|:--|:--
+|`INTERFACE`|[Block](#struct_Block)|标识模块化服务为阻塞进程的服务,当实现了 Service 且实现了 Block 接口时,模块化应用程序会在 Service.OnMount 阶段完成后执行 OnBlock 函数
+|`INTERFACE`|[Service](#struct_Service)|模块化服务接口,所有的服务均需要实现该接口,在服务的生命周期内发生任何错误均应通过 panic 阻止服务继续运行
+
+
+
+
+***
+## 详情信息
+#### func Run()
+
+> 运行模块化应用程序
+
+***
+#### func RegisterServices(s ...Service)
+
+> 注册服务
+
+***
+
+### Block `INTERFACE`
+标识模块化服务为阻塞进程的服务,当实现了 Service 且实现了 Block 接口时,模块化应用程序会在 Service.OnMount 阶段完成后执行 OnBlock 函数
+
+该接口适用于 Http 服务、WebSocket 服务等需要阻塞进程的服务。需要注意的是, OnBlock 的执行不能保证按照 Service 的注册顺序执行
+```go
+type Block interface {
+ Service
+ OnBlock()
+}
+```
+
+### Service `INTERFACE`
+模块化服务接口,所有的服务均需要实现该接口,在服务的生命周期内发生任何错误均应通过 panic 阻止服务继续运行
+ - 生命周期示例: OnInit -> OnPreload -> OnMount
+
+在 Golang 中,包与包之间互相引用会导致循环依赖,因此在模块化应用程序中,所有的服务均不应该直接引用其他服务。
+
+服务应该在 OnInit 阶段将不依赖其他服务的内容初始化完成,并且如果服务需要暴露给其他服务调用,那么也应该在 OnInit 阶段完成对外暴露。
+ - 暴露方式可参考 modular/example
+
+在 OnPreload 阶段,服务应该完成对其依赖服务的依赖注入,最终在 OnMount 阶段完成对服务功能的定义、路由的声明等。
+```go
+type Service interface {
+ OnInit()
+ OnPreload()
+ OnMount()
+}
+```
diff --git a/modular/example/README.md b/modular/example/README.md
new file mode 100644
index 0000000..a526d73
--- /dev/null
+++ b/modular/example/README.md
@@ -0,0 +1,15 @@
+# Main
+
+[](https://pkg.go.dev/github.com/kercylan98/minotaur)
+
+
+暂无介绍...
+
+
+
+
+
+
+
+
+***
diff --git a/modular/example/internal/service/expose/README.md b/modular/example/internal/service/expose/README.md
new file mode 100644
index 0000000..0536fdd
--- /dev/null
+++ b/modular/example/internal/service/expose/README.md
@@ -0,0 +1,42 @@
+# Expose
+
+[](https://pkg.go.dev/github.com/kercylan98/minotaur)
+
+
+暂无介绍...
+
+
+## 目录导航
+列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
+
+展开 / 折叠目录导航
+
+
+> 类型定义
+
+|类型|名称|描述
+|:--|:--|:--
+|`INTERFACE`|[Attack](#struct_Attack)|暂无描述...
+|`INTERFACE`|[Login](#struct_Login)|暂无描述...
+
+
+
+
+***
+## 详情信息
+
+### Attack `INTERFACE`
+
+```go
+type Attack interface {
+ Name() string
+}
+```
+
+### Login `INTERFACE`
+
+```go
+type Login interface {
+ Name() string
+}
+```
diff --git a/modular/example/internal/service/services/attack/README.md b/modular/example/internal/service/services/attack/README.md
new file mode 100644
index 0000000..a78a2b2
--- /dev/null
+++ b/modular/example/internal/service/services/attack/README.md
@@ -0,0 +1,54 @@
+# Attack
+
+[](https://pkg.go.dev/github.com/kercylan98/minotaur)
+
+
+暂无介绍...
+
+
+## 目录导航
+列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
+
+展开 / 折叠目录导航
+
+
+> 类型定义
+
+|类型|名称|描述
+|:--|:--|:--
+|`STRUCT`|[Service](#struct_Service)|暂无描述...
+
+
+
+
+***
+## 详情信息
+
+### Service `STRUCT`
+
+```go
+type Service struct {
+ Login expose.Login
+ name string
+}
+```
+
+
+#### func (*Service) OnInit()
+
+***
+
+
+#### func (*Service) OnPreload()
+
+***
+
+
+#### func (*Service) OnMount()
+
+***
+
+
+#### func (*Service) Name() string
+
+***
diff --git a/modular/example/internal/service/services/login/README.md b/modular/example/internal/service/services/login/README.md
new file mode 100644
index 0000000..f00438a
--- /dev/null
+++ b/modular/example/internal/service/services/login/README.md
@@ -0,0 +1,54 @@
+# Login
+
+[](https://pkg.go.dev/github.com/kercylan98/minotaur)
+
+
+暂无介绍...
+
+
+## 目录导航
+列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
+
+展开 / 折叠目录导航
+
+
+> 类型定义
+
+|类型|名称|描述
+|:--|:--|:--
+|`STRUCT`|[Service](#struct_Service)|暂无描述...
+
+
+
+
+***
+## 详情信息
+
+### Service `STRUCT`
+
+```go
+type Service struct {
+ Attack expose.Attack
+ name string
+}
+```
+
+
+#### func (*Service) OnInit()
+
+***
+
+
+#### func (*Service) OnPreload()
+
+***
+
+
+#### func (*Service) OnMount()
+
+***
+
+
+#### func (*Service) Name() string
+
+***
diff --git a/modular/example/internal/service/services/server/README.md b/modular/example/internal/service/services/server/README.md
new file mode 100644
index 0000000..b3dbb5b
--- /dev/null
+++ b/modular/example/internal/service/services/server/README.md
@@ -0,0 +1,53 @@
+# Server
+
+[](https://pkg.go.dev/github.com/kercylan98/minotaur)
+
+
+暂无介绍...
+
+
+## 目录导航
+列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
+
+展开 / 折叠目录导航
+
+
+> 类型定义
+
+|类型|名称|描述
+|:--|:--|:--
+|`STRUCT`|[Service](#struct_Service)|暂无描述...
+
+
+
+
+***
+## 详情信息
+
+### Service `STRUCT`
+
+```go
+type Service struct {
+ srv *server.Server
+}
+```
+
+
+#### func (*Service) OnInit()
+
+***
+
+
+#### func (*Service) OnPreload()
+
+***
+
+
+#### func (*Service) OnMount()
+
+***
+
+
+#### func (*Service) OnBlock()
+
+***
diff --git a/utils/generator/astgo/type.go b/utils/generator/astgo/type.go
index c30a7a4..4e4baf9 100644
--- a/utils/generator/astgo/type.go
+++ b/utils/generator/astgo/type.go
@@ -50,7 +50,7 @@ func newType(expr ast.Expr) *Type {
params = append(params, fmt.Sprintf("%s %s", f.Name, f.Type.Sign))
}
s = strings.Join(params, ", ")
- if brackets {
+ if brackets && strings.HasSuffix(s, ")") && strings.HasPrefix(s, "(") {
s = "(" + s + ")"
}
}
diff --git a/utils/stream/README.md b/utils/stream/README.md
new file mode 100644
index 0000000..7c636fd
--- /dev/null
+++ b/utils/stream/README.md
@@ -0,0 +1,1595 @@
+# Stream
+
+[](https://pkg.go.dev/github.com/kercylan98/minotaur)
+
+
+暂无介绍...
+
+
+## 目录导航
+列出了该 `package` 下所有的函数及类型定义,可通过目录导航进行快捷跳转 ❤️
+
+展开 / 折叠目录导航
+
+
+> 包级函数定义
+
+|函数名称|描述
+|:--|:--
+|[NewString](#NewString)|创建字符串流
+|[NewStrings](#NewStrings)|创建字符串切片
+
+
+> 类型定义
+
+|类型|名称|描述
+|:--|:--|:--
+|`STRUCT`|[String](#struct_String)|字符串流
+|`STRUCT`|[Strings](#struct_Strings)|字符串切片
+
+
+
+
+***
+## 详情信息
+#### func NewString\[S ~string\](s S) *String[S]
+
+> 创建字符串流
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestNewString(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "hello", want: "hello"}, {name: "case2", in: "world", want: "world"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in)
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s) = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+#### func NewStrings\[S ~string\](s ...S) *Strings[S]
+
+> 创建字符串切片
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestNewStrings(t *testing.T) {
+ var cases = []struct {
+ name string
+ in []string
+ want []string
+ }{{name: "empty", in: []string{}, want: []string{}}, {name: "one", in: []string{"a"}, want: []string{"a"}}, {name: "two", in: []string{"a", "b"}, want: []string{"a", "b"}}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewStrings(c.in...)
+ if got.Len() != len(c.want) {
+ t.Errorf("got %v, want %v", got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+### String `STRUCT`
+字符串流
+```go
+type String[S ~string] struct {
+ str S
+}
+```
+
+
+#### func (*String) Elem() S
+> 返回原始元素
+
+***
+
+
+#### func (*String) String() string
+> 返回字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_String(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "hello", want: "hello"}, {name: "case2", in: "world", want: "world"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).String()
+ if got != c.want {
+ t.Fatalf("String(%s).String() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Index(i int) *String[S]
+> 返回字符串指定位置的字符,当索引超出范围时将会触发 panic
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Index(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ i int
+ want string
+ shouldPanic bool
+ }{{name: "case1", in: "hello", i: 0, want: "h", shouldPanic: false}, {name: "case2", in: "world", i: 2, want: "r", shouldPanic: false}, {name: "case3", in: "world", i: 5, want: "", shouldPanic: true}, {name: "case4", in: "world", i: -1, want: "", shouldPanic: true}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ defer func() {
+ if r := recover(); (r != nil) != c.shouldPanic {
+ t.Fatalf("NewString(%s).Index(%d) should panic", c.in, c.i)
+ }
+ }()
+ got := stream.NewString(c.in).Index(c.i)
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).Index(%d) = %s; want %s", c.in, c.i, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Range(start int, end int) *String[S]
+> 返回字符串指定范围的字符
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Range(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ start int
+ end int
+ want string
+ shouldPanic bool
+ }{{name: "case1", in: "hello", start: 0, end: 2, want: "he", shouldPanic: false}, {name: "case2", in: "world", start: 2, end: 5, want: "rld", shouldPanic: false}, {name: "case3", in: "world", start: 5, end: 6, want: "", shouldPanic: true}, {name: "case4", in: "world", start: -1, end: 6, want: "", shouldPanic: true}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ defer func() {
+ if r := recover(); (r != nil) != c.shouldPanic {
+ t.Fatalf("NewString(%s).Range(%d, %d) should panic", c.in, c.start, c.end)
+ }
+ }()
+ got := stream.NewString(c.in).Range(c.start, c.end)
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).Range(%d, %d) = %s; want %s", c.in, c.start, c.end, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) TrimSpace() *String[S]
+> 返回去除字符串首尾空白字符的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_TrimSpace(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: " hello ", want: "hello"}, {name: "case2", in: " world ", want: "world"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).TrimSpace()
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).TrimSpace() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Trim(cs string) *String[S]
+> 返回去除字符串首尾指定字符的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Trim(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ cs string
+ want string
+ }{{name: "case1", in: "hello", cs: "h", want: "ello"}, {name: "case2", in: "world", cs: "d", want: "worl"}, {name: "none", in: "world", cs: "", want: "world"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Trim(c.cs)
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).Trim(%s) = %s; want %s", c.in, c.cs, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) TrimPrefix(prefix string) *String[S]
+> 返回去除字符串前缀的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_TrimPrefix(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ prefix string
+ want string
+ isEqual bool
+ }{{name: "case1", in: "hello", prefix: "h", want: "ello", isEqual: false}, {name: "case2", in: "world", prefix: "w", want: "orld", isEqual: false}, {name: "none", in: "world", prefix: "x", want: "world", isEqual: true}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).TrimPrefix(c.prefix)
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).TrimPrefix(%s) = %s; want %s", c.in, c.prefix, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) TrimSuffix(suffix string) *String[S]
+> 返回去除字符串后缀的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_TrimSuffix(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ suffix string
+ want string
+ isEqual bool
+ }{{name: "case1", in: "hello", suffix: "o", want: "hell", isEqual: false}, {name: "case2", in: "world", suffix: "d", want: "worl", isEqual: false}, {name: "none", in: "world", suffix: "x", want: "world", isEqual: true}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).TrimSuffix(c.suffix)
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).TrimSuffix(%s) = %s; want %s", c.in, c.suffix, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) ToUpper() *String[S]
+> 返回字符串的大写形式
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_ToUpper(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "hello", want: "HELLO"}, {name: "case2", in: "world", want: "WORLD"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).ToUpper()
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).ToUpper() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) ToLower() *String[S]
+> 返回字符串的小写形式
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_ToLower(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "HELLO", want: "hello"}, {name: "case2", in: "WORLD", want: "world"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).ToLower()
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).ToLower() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Equal(ss S) bool
+> 返回字符串是否相等
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Equal(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ ss string
+ want bool
+ }{{name: "case1", in: "hello", ss: "hello", want: true}, {name: "case2", in: "world", ss: "world", want: true}, {name: "case3", in: "world", ss: "worldx", want: false}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Equal(c.ss)
+ if got != c.want {
+ t.Fatalf("NewString(%s).Equal(%s) = %t; want %t", c.in, c.ss, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) HasPrefix(prefix S) bool
+> 返回字符串是否包含指定前缀
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_HasPrefix(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ prefix string
+ want bool
+ }{{name: "case1", in: "hello", prefix: "h", want: true}, {name: "case2", in: "world", prefix: "w", want: true}, {name: "case3", in: "world", prefix: "x", want: false}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).HasPrefix(c.prefix)
+ if got != c.want {
+ t.Fatalf("NewString(%s).HasPrefix(%s) = %t; want %t", c.in, c.prefix, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) HasSuffix(suffix S) bool
+> 返回字符串是否包含指定后缀
+
+***
+
+
+#### func (*String) Len() int
+> 返回字符串长度
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Len(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want int
+ }{{name: "case1", in: "hello", want: 5}, {name: "case2", in: "world", want: 5}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Len()
+ if got != c.want {
+ t.Fatalf("NewString(%s).Len() = %d; want %d", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Contains(sub S) bool
+> 返回字符串是否包含指定子串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Contains(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ ss string
+ want bool
+ }{{name: "case1", in: "hello", ss: "he", want: true}, {name: "case2", in: "world", ss: "or", want: true}, {name: "case3", in: "world", ss: "x", want: false}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Contains(c.ss)
+ if got != c.want {
+ t.Fatalf("NewString(%s).Contains(%s) = %t; want %t", c.in, c.ss, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Count(sub S) int
+> 返回字符串包含指定子串的次数
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Count(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ ss string
+ want int
+ }{{name: "case1", in: "hello", ss: "l", want: 2}, {name: "case2", in: "world", ss: "o", want: 1}, {name: "case3", in: "world", ss: "x", want: 0}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Count(c.ss)
+ if got != c.want {
+ t.Fatalf("NewString(%s).Count(%s) = %d; want %d", c.in, c.ss, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Repeat(count int) *String[S]
+> 返回重复 count 次的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Repeat(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ count int
+ want string
+ }{{name: "case1", in: "hello", count: 2, want: "hellohello"}, {name: "case2", in: "world", count: 3, want: "worldworldworld"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Repeat(c.count)
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).Repeat(%d) = %s; want %s", c.in, c.count, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Replace(old S, new S, n int) *String[S]
+> 返回替换指定子串后的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Replace(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ old string
+ new string
+ want string
+ }{{name: "case1", in: "hello", old: "l", new: "x", want: "hexxo"}, {name: "case2", in: "world", old: "o", new: "x", want: "wxrld"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Replace(c.old, c.new, -1)
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).Replace(%s, %s) = %s; want %s", c.in, c.old, c.new, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) ReplaceAll(old S, new S) *String[S]
+> 返回替换所有指定子串后的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_ReplaceAll(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ old string
+ new string
+ want string
+ }{{name: "case1", in: "hello", old: "l", new: "x", want: "hexxo"}, {name: "case2", in: "world", old: "o", new: "x", want: "wxrld"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).ReplaceAll(c.old, c.new)
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).ReplaceAll(%s, %s) = %s; want %s", c.in, c.old, c.new, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Append(ss S) *String[S]
+> 返回追加指定字符串后的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Append(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ ss string
+ want string
+ }{{name: "case1", in: "hello", ss: " world", want: "hello world"}, {name: "case2", in: "world", ss: " hello", want: "world hello"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Append(c.ss)
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).Append(%s) = %s; want %s", c.in, c.ss, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Prepend(ss S) *String[S]
+> 返回追加指定字符串后的字符串,追加的字符串在前
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Prepend(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ ss string
+ want string
+ }{{name: "case1", in: "hello", ss: "world ", want: "world hello"}, {name: "case2", in: "world", ss: "hello ", want: "hello world"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Prepend(c.ss)
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).Prepend(%s) = %s; want %s", c.in, c.ss, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Clear() *String[S]
+> 返回清空字符串后的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Clear(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "hello", want: ""}, {name: "case2", in: "world", want: ""}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Clear()
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).Clear() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Reverse() *String[S]
+> 返回反转字符串后的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Reverse(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "hello", want: "olleh"}, {name: "case2", in: "world", want: "dlrow"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Reverse()
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).Reverse() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Queto() *String[S]
+> 返回带引号的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Queto(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "hello", want: "\"hello\""}, {name: "case2", in: "world", want: "\"world\""}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Queto()
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).Queto() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) QuetoToASCII() *String[S]
+> 返回带引号的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_QuetoToASCII(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "hello", want: "\"hello\""}, {name: "case2", in: "world", want: "\"world\""}, {name: "case3", in: "你好", want: "\"\\u4f60\\u597d\""}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).QuetoToASCII()
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).QuetoToASCII() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) FirstUpper() *String[S]
+> 返回首字母大写的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_FirstUpper(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "hello", want: "Hello"}, {name: "case2", in: "world", want: "World"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).FirstUpper()
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).FirstUpper() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) FirstLower() *String[S]
+> 返回首字母小写的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_FirstLower(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "Hello", want: "hello"}, {name: "case2", in: "World", want: "world"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).FirstLower()
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).FirstLower() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) SnakeCase() *String[S]
+> 返回蛇形命名的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_SnakeCase(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "HelloWorld", want: "hello_world"}, {name: "case2", in: "HelloWorldHello", want: "hello_world_hello"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).SnakeCase()
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).SnakeCase() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) CamelCase() *String[S]
+> 返回驼峰命名的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_CamelCase(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "hello_world", want: "helloWorld"}, {name: "case2", in: "hello_world_hello", want: "helloWorldHello"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).CamelCase()
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).CamelCase() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) KebabCase() *String[S]
+> 返回短横线命名的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_KebabCase(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "HelloWorld", want: "hello-world"}, {name: "case2", in: "HelloWorldHello", want: "hello-world-hello"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).KebabCase()
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).KebabCase() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) TitleCase() *String[S]
+> 返回标题命名的字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_TitleCase(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "hello_world", want: "HelloWorld"}, {name: "case2", in: "hello_world_hello", want: "HelloWorldHello"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).TitleCase()
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).TitleCase() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Bytes() []byte
+> 返回字符串的字节数组
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Bytes(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "hello", want: "hello"}, {name: "case2", in: "world", want: "world"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Bytes()
+ if string(got) != c.want {
+ t.Fatalf("NewString(%s).Bytes() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Runes() []rune
+> 返回字符串的字符数组
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Runes(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "hello", want: "hello"}, {name: "case2", in: "world", want: "world"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Runes()
+ if string(got) != c.want {
+ t.Fatalf("NewString(%s).Runes() = %v; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Default(def S) *String[S]
+> 当字符串为空时设置默认值
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Default(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "", want: "default"}, {name: "case2", in: "world", want: "world"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Default("default")
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).Default() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Handle(f func ( S)) *String[S]
+> 处理字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Handle(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "hello", want: "hello"}, {name: "case2", in: "world", want: "world"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ var w string
+ got := stream.NewString(c.in).Handle(func(s string) {
+ w = s
+ })
+ if w != c.want {
+ t.Fatalf("NewString(%s).Handle() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Update(f func ( S) S) *String[S]
+> 更新字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Update(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ want string
+ }{{name: "case1", in: "hello", want: "HELLO"}, {name: "case2", in: "world", want: "WORLD"}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Update(func(s string) string {
+ return stream.NewString(s).ToUpper().String()
+ })
+ if got.String() != c.want {
+ t.Fatalf("NewString(%s).Update() = %s; want %s", c.in, got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Split(sep string) *Strings[S]
+> 返回字符串切片
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Split(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ sep string
+ want []string
+ }{{name: "case1", in: "hello world", sep: " ", want: []string{"hello", "world"}}, {name: "case2", in: "hello,world", sep: ",", want: []string{"hello", "world"}}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Split(c.sep)
+ for i, v := range got.Elem() {
+ if v != c.want[i] {
+ t.Fatalf("NewString(%s).Split(%s) = %v; want %v", c.in, c.sep, got, c.want)
+ }
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) SplitN(sep string, n int) *Strings[S]
+> 返回字符串切片
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_SplitN(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ sep string
+ n int
+ want []string
+ }{{name: "case1", in: "hello world", sep: " ", n: 2, want: []string{"hello", "world"}}, {name: "case2", in: "hello,world", sep: ",", n: 2, want: []string{"hello", "world"}}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).SplitN(c.sep, c.n)
+ for i, v := range got.Elem() {
+ if v != c.want[i] {
+ t.Fatalf("NewString(%s).SplitN(%s, %d) = %v; want %v", c.in, c.sep, c.n, got, c.want)
+ }
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*String) Batched(size int) *Strings[S]
+> 将字符串按照指定长度分组,最后一组可能小于指定长度
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestString_Batched(t *testing.T) {
+ var cases = []struct {
+ name string
+ in string
+ size int
+ want []string
+ }{{name: "case1", in: "hello world", size: 5, want: []string{"hello", " worl", "d"}}, {name: "case2", in: "hello,world", size: 5, want: []string{"hello", ",worl", "d"}}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewString(c.in).Batched(c.size)
+ for i, v := range got.Elem() {
+ if v != c.want[i] {
+ t.Fatalf("NewString(%s).Batched(%d) = %v; want %v", c.in, c.size, got, c.want)
+ }
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+### Strings `STRUCT`
+字符串切片
+```go
+type Strings[S ~string] struct {
+ s []S
+}
+```
+
+
+#### func (*Strings) Elem() []S
+> 返回原始元素
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestStrings_Elem(t *testing.T) {
+ var cases = []struct {
+ name string
+ in []string
+ want []string
+ }{{name: "empty", in: []string{}, want: []string{}}, {name: "one", in: []string{"a"}, want: []string{"a"}}, {name: "two", in: []string{"a", "b"}, want: []string{"a", "b"}}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewStrings(c.in...).Elem()
+ if len(got) != len(c.want) {
+ t.Errorf("got %v, want %v", got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*Strings) Len() int
+> 返回切片长度
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestStrings_Len(t *testing.T) {
+ var cases = []struct {
+ name string
+ in []string
+ want int
+ }{{name: "empty", in: []string{}, want: 0}, {name: "one", in: []string{"a"}, want: 1}, {name: "two", in: []string{"a", "b"}, want: 2}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewStrings(c.in...)
+ if got.Len() != c.want {
+ t.Errorf("got %v, want %v", got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*Strings) Append(ss ...S) *Strings[S]
+> 添加字符串
+
+
+查看 / 收起单元测试
+
+
+```go
+
+func TestStrings_Append(t *testing.T) {
+ var cases = []struct {
+ name string
+ in []string
+ append []string
+ want []string
+ }{{name: "empty", in: []string{}, append: []string{"a"}, want: []string{"a"}}, {name: "one", in: []string{"a"}, append: []string{"b"}, want: []string{"a", "b"}}, {name: "two", in: []string{"a", "b"}, append: []string{"c"}, want: []string{"a", "b", "c"}}}
+ for _, c := range cases {
+ t.Run(c.name, func(t *testing.T) {
+ got := stream.NewStrings(c.in...).Append(c.append...)
+ if got.Len() != len(c.want) {
+ t.Errorf("got %v, want %v", got, c.want)
+ }
+ })
+ }
+}
+
+```
+
+
+
+
+
+***
+
+
+#### func (*Strings) Join(sep S) *String[S]
+> 连接字符串
+
+***
+
+
+#### func (*Strings) Choice(i int) *String[S]
+> 选择字符串
+
+***
+
+
+#### func (*Strings) Choices(i ...int) *Strings[S]
+> 选择多个字符串
+
+***
+
+
+#### func (*Strings) ChoiceInRange(start int, end int) *Strings[S]
+> 选择范围内的字符串
+
+***
+
+
+#### func (*Strings) Remove(i int) *Strings[S]
+> 移除字符串
+
+***
+
+
+#### func (*Strings) Removes(i ...int) *Strings[S]
+> 移除多个字符串
+
+***
+
+
+#### func (*Strings) RemoveInRange(start int, end int) *Strings[S]
+> 移除范围内的字符串
+
+***
+
+
+#### func (*Strings) Clear() *Strings[S]
+> 清空字符串
+
+***
+
+
+#### func (*Strings) First() *String[S]
+> 第一个字符串
+
+***
+
+
+#### func (*Strings) Last() *String[S]
+> 最后一个字符串
+
+***