mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-11 16:22:26 +08:00
Compare commits
76 Commits
v2.1.12
...
4c5524354c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c5524354c | ||
|
|
2c6e9a3fb9 | ||
|
|
5f2c3edff4 | ||
|
|
b422d98702 | ||
|
|
6f27e0bfbf | ||
|
|
ce3b6b461e | ||
|
|
0d6ad4f0d2 | ||
|
|
c875a7f8b8 | ||
|
|
0c62d117a1 | ||
|
|
c260ce493d | ||
|
|
9ffe96d3ef | ||
|
|
d4bba76dc8 | ||
|
|
adaa3ebc43 | ||
|
|
61d38ae3b8 | ||
|
|
c85d910044 | ||
|
|
d95a7c6101 | ||
|
|
bce3641ec6 | ||
|
|
ceb134b2fd | ||
|
|
4b9b1d32c5 | ||
|
|
395e0883c7 | ||
|
|
a930511054 | ||
|
|
7380721ccc | ||
|
|
936011dc3b | ||
|
|
bc0ee08f38 | ||
|
|
f1afd753d4 | ||
|
|
b05a0a91c3 | ||
|
|
da2eb66657 | ||
|
|
ad20159de2 | ||
|
|
278733d3d1 | ||
|
|
2f184907ff | ||
|
|
50fcc718ee | ||
|
|
cc68feb52d | ||
|
|
ca2a51b37e | ||
|
|
be444f521d | ||
|
|
e21dd07d46 | ||
|
|
4044deac70 | ||
|
|
d9c6294775 | ||
|
|
d8505d1a5f | ||
|
|
6498c7d68a | ||
|
|
5f0211f0c4 | ||
|
|
1de2e2cedd | ||
|
|
c8f8b1b7d9 | ||
|
|
3062eb7789 | ||
|
|
64d5486cc6 | ||
|
|
6d57891f66 | ||
|
|
927245e47f | ||
|
|
31fdbee0b5 | ||
|
|
3712819994 | ||
|
|
6d7dec1cea | ||
|
|
9b6a004dbc | ||
|
|
3ad6f4bd9e | ||
|
|
b8c6746f31 | ||
|
|
0bf8bbf4cb | ||
|
|
a6ba1028c5 | ||
|
|
cc54dd7ec9 | ||
|
|
54834dba4c | ||
|
|
e996d4c945 | ||
|
|
ae92ae7666 | ||
|
|
526e568d0e | ||
|
|
1dc5e8ac23 | ||
|
|
b5f7b0e670 | ||
|
|
39c576248c | ||
|
|
eb164d1536 | ||
|
|
68e170080c | ||
|
|
652b09135c | ||
|
|
bff24c89bc | ||
|
|
49a460eef8 | ||
|
|
a58e52e53c | ||
|
|
b07356423f | ||
|
|
005dd9d2ab | ||
|
|
65315dafb1 | ||
|
|
b06fb6736d | ||
|
|
b9f0854950 | ||
|
|
6a2dd328ad | ||
|
|
dd1147f6d0 | ||
|
|
6da7ce64af |
1246
README_zh-CN.md
1246
README_zh-CN.md
File diff suppressed because it is too large
Load Diff
@@ -26,7 +26,7 @@ type LRUCache[K comparable, V any] struct {
|
||||
length int
|
||||
}
|
||||
|
||||
// NewLRUCache return a LRUCache pointer
|
||||
// NewLRUCache creates a LRUCache pointer instance.
|
||||
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
|
||||
return &LRUCache[K, V]{
|
||||
cache: make(map[K]*lruNode[K, V], capacity),
|
||||
@@ -37,7 +37,8 @@ func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
|
||||
}
|
||||
}
|
||||
|
||||
// Get value of key from lru cache
|
||||
// Get value of key from lru cache.
|
||||
// Play: https://go.dev/play/p/iUynEfOP8G0
|
||||
func (l *LRUCache[K, V]) Get(key K) (V, bool) {
|
||||
var value V
|
||||
|
||||
@@ -50,7 +51,8 @@ func (l *LRUCache[K, V]) Get(key K) (V, bool) {
|
||||
return value, false
|
||||
}
|
||||
|
||||
// Put value of key into lru cache
|
||||
// Put value of key into lru cache.
|
||||
// Play: https://go.dev/play/p/iUynEfOP8G0
|
||||
func (l *LRUCache[K, V]) Put(key K, value V) {
|
||||
node, ok := l.cache[key]
|
||||
if !ok {
|
||||
@@ -69,6 +71,23 @@ func (l *LRUCache[K, V]) Put(key K, value V) {
|
||||
l.length = len(l.cache)
|
||||
}
|
||||
|
||||
// Delete item from lru cache.
|
||||
func (l *LRUCache[K, V]) Delete(key K) bool {
|
||||
node, ok := l.cache[key]
|
||||
if ok {
|
||||
key := l.deleteNode(node)
|
||||
delete(l.cache, key)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Len returns the number of items in the cache.
|
||||
func (l *LRUCache[K, V]) Len() int {
|
||||
return l.length
|
||||
}
|
||||
|
||||
func (l *LRUCache[K, V]) addNode(node *lruNode[K, V]) {
|
||||
if l.tail != nil {
|
||||
l.tail.next = node
|
||||
79
algorithm/lrucache_example_test.go
Normal file
79
algorithm/lrucache_example_test.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package algorithm
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleLRUCache_Put() {
|
||||
cache := NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
result1, ok1 := cache.Get(1)
|
||||
result2, ok2 := cache.Get(2)
|
||||
result3, ok3 := cache.Get(3)
|
||||
|
||||
fmt.Println(result1, ok1)
|
||||
fmt.Println(result2, ok2)
|
||||
fmt.Println(result3, ok3)
|
||||
|
||||
// Output:
|
||||
// 1 true
|
||||
// 2 true
|
||||
// 0 false
|
||||
}
|
||||
|
||||
func ExampleLRUCache_Get() {
|
||||
cache := NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
result1, ok1 := cache.Get(1)
|
||||
result2, ok2 := cache.Get(2)
|
||||
result3, ok3 := cache.Get(3)
|
||||
|
||||
fmt.Println(result1, ok1)
|
||||
fmt.Println(result2, ok2)
|
||||
fmt.Println(result3, ok3)
|
||||
|
||||
// Output:
|
||||
// 1 true
|
||||
// 2 true
|
||||
// 0 false
|
||||
}
|
||||
|
||||
func ExampleLRUCache_Delete() {
|
||||
cache := NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
result1, ok1 := cache.Get(1)
|
||||
|
||||
ok2 := cache.Delete(2)
|
||||
|
||||
_, ok3 := cache.Get(2)
|
||||
|
||||
fmt.Println(result1, ok1)
|
||||
fmt.Println(ok2)
|
||||
fmt.Println(ok3)
|
||||
|
||||
// Output:
|
||||
// 1 true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleLRUCache_Len() {
|
||||
cache := NewLRUCache[int, int](2)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
result := cache.Len()
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
func TestLRUCache(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestLRUCache")
|
||||
|
||||
cache := NewLRUCache[int, int](2)
|
||||
cache := NewLRUCache[int, int](3)
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
cache.Put(3, 3)
|
||||
|
||||
_, ok := cache.Get(0)
|
||||
asssert.Equal(false, ok)
|
||||
asssert.Equal(3, cache.Len())
|
||||
|
||||
v, ok := cache.Get(1)
|
||||
asssert.Equal(true, ok)
|
||||
@@ -25,12 +25,9 @@ func TestLRUCache(t *testing.T) {
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(2, v)
|
||||
|
||||
cache.Put(3, 3)
|
||||
v, ok = cache.Get(1)
|
||||
asssert.Equal(false, ok)
|
||||
asssert.NotEqual(1, v)
|
||||
|
||||
v, ok = cache.Get(3)
|
||||
ok = cache.Delete(2)
|
||||
asssert.Equal(true, ok)
|
||||
asssert.Equal(3, v)
|
||||
|
||||
_, ok = cache.Get(2)
|
||||
asssert.Equal(false, ok)
|
||||
}
|
||||
@@ -1,26 +1,28 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package algorithm contain some basic algorithm functions. eg. sort, search, list, linklist, stack, queue, tree, graph. TODO
|
||||
// Package algorithm contain some basic algorithm functions. eg. sort, search, list, linklist, stack, queue, tree, graph.
|
||||
package algorithm
|
||||
|
||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
|
||||
// Search algorithms see https://github.com/TheAlgorithms/Go/tree/master/search
|
||||
|
||||
// LinearSearch Simple linear search algorithm that iterates over all elements of an slice
|
||||
// If a target is found, the index of the target is returned. Else the function return -1
|
||||
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int {
|
||||
// LinearSearch return the index of target in slice base on equal function.
|
||||
// If not found return -1
|
||||
// Play: https://go.dev/play/p/IsS7rgn5s3x
|
||||
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int {
|
||||
for i, v := range slice {
|
||||
if comparator.Compare(v, target) == 0 {
|
||||
if equal(v, target) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// BinarySearch search for target within a sorted slice, recursive call itself.
|
||||
// If a target is found, the index of the target is returned. Else the function return -1
|
||||
// BinarySearch return the index of target within a sorted slice, use binary search (recursive call itself).
|
||||
// If not found return -1.
|
||||
// Play: https://go.dev/play/p/t6MeGiUSN47
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||
if highIndex < lowIndex || len(sortedSlice) == 0 {
|
||||
return -1
|
||||
@@ -39,8 +41,9 @@ func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, com
|
||||
return midIndex
|
||||
}
|
||||
|
||||
// BinaryIterativeSearch search for target within a sorted slice.
|
||||
// If a target is found, the index of the target is returned. Else the function return -1
|
||||
// BinaryIterativeSearch return the index of target within a sorted slice, use binary search (no recursive).
|
||||
// If not found return -1.
|
||||
// Play: https://go.dev/play/p/Anozfr8ZLH3
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||
startIndex := lowIndex
|
||||
endIndex := highIndex
|
||||
|
||||
51
algorithm/search_example_test.go
Normal file
51
algorithm/search_example_test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package algorithm
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleLinearSearch() {
|
||||
numbers := []int{3, 4, 5, 3, 2, 1}
|
||||
|
||||
equalFunc := func(a, b int) bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
result1 := LinearSearch(numbers, 3, equalFunc)
|
||||
result2 := LinearSearch(numbers, 6, equalFunc)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// -1
|
||||
}
|
||||
|
||||
func ExampleBinarySearch() {
|
||||
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
result1 := BinarySearch(numbers, 5, 0, len(numbers)-1, comparator)
|
||||
result2 := BinarySearch(numbers, 9, 0, len(numbers)-1, comparator)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// -1
|
||||
}
|
||||
|
||||
func ExampleBinaryIterativeSearch() {
|
||||
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
result1 := BinaryIterativeSearch(numbers, 5, 0, len(numbers)-1, comparator)
|
||||
result2 := BinaryIterativeSearch(numbers, 9, 0, len(numbers)-1, comparator)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// -1
|
||||
}
|
||||
@@ -6,20 +6,24 @@ import (
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
|
||||
func TestLinearSearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestLinearSearch")
|
||||
|
||||
comparator := &intComparator{}
|
||||
asssert.Equal(4, LinearSearch(sortedNumbers, 5, comparator))
|
||||
asssert.Equal(-1, LinearSearch(sortedNumbers, 9, comparator))
|
||||
numbers := []int{3, 4, 5, 3, 2, 1}
|
||||
equalFunc := func(a, b int) bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
asssert.Equal(0, LinearSearch(numbers, 3, equalFunc))
|
||||
asssert.Equal(-1, LinearSearch(numbers, 6, equalFunc))
|
||||
}
|
||||
|
||||
func TestBinarySearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBinarySearch")
|
||||
|
||||
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
asssert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
asssert.Equal(-1, BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
}
|
||||
@@ -27,7 +31,9 @@ func TestBinarySearch(t *testing.T) {
|
||||
func TestBinaryIterativeSearch(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBinaryIterativeSearch")
|
||||
|
||||
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
|
||||
asssert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||
asssert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package algorithm contain some basic algorithm functions. eg. sort, search
|
||||
package algorithm
|
||||
|
||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||
|
||||
// BubbleSort use bubble to sort slice.
|
||||
// BubbleSort applys the bubble sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/GNdv7Jg2Taj
|
||||
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
for j := 0; j < len(slice)-1-i; j++ {
|
||||
@@ -18,7 +18,8 @@ func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
// InsertionSort use insertion to sort slice.
|
||||
// InsertionSort applys the insertion sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/G5LJiWgJJW6
|
||||
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
for j := i; j > 0; j-- {
|
||||
@@ -32,7 +33,8 @@ func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
// SelectionSort use selection to sort slice.
|
||||
// SelectionSort applys the selection sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/oXovbkekayS
|
||||
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
for i := 0; i < len(slice); i++ {
|
||||
min := i
|
||||
@@ -45,7 +47,8 @@ func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
// ShellSort shell sort slice.
|
||||
// ShellSort applys the shell sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/3ibkszpJEu3
|
||||
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
size := len(slice)
|
||||
|
||||
@@ -64,7 +67,8 @@ func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
}
|
||||
}
|
||||
|
||||
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1
|
||||
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1.
|
||||
// Play: https://go.dev/play/p/7Y7c1Elk3ax
|
||||
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
quickSort(slice, 0, len(slice)-1, comparator)
|
||||
}
|
||||
@@ -93,7 +97,8 @@ func partition[T any](slice []T, lowIndex, highIndex int, comparator lancetconst
|
||||
return i
|
||||
}
|
||||
|
||||
// HeapSort use heap to sort slice
|
||||
// HeapSort applys the heap sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/u6Iwa1VZS_f
|
||||
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
size := len(slice)
|
||||
|
||||
@@ -126,7 +131,8 @@ func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraint
|
||||
slice[i] = temp
|
||||
}
|
||||
|
||||
// MergeSort merge sorting for slice
|
||||
// MergeSort applys the merge sort algorithm to sort the collection, will change the original collection data.
|
||||
// Play: https://go.dev/play/p/ydinn9YzUJn
|
||||
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||
mergeSort(slice, 0, len(slice)-1, comparator)
|
||||
}
|
||||
@@ -167,7 +173,8 @@ func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator lance
|
||||
}
|
||||
}
|
||||
|
||||
// CountSort use count sorting for slice
|
||||
// CountSort applys the count sort algorithm to sort the collection, don't change the original collection data.
|
||||
// Play: https://go.dev/play/p/tB-Umgm0DrP
|
||||
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T {
|
||||
size := len(slice)
|
||||
out := make([]T, size)
|
||||
|
||||
93
algorithm/sort_example_test.go
Normal file
93
algorithm/sort_example_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package algorithm
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleBubbleSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
BubbleSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleCountSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
sortedNumber := CountSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
fmt.Println(sortedNumber)
|
||||
// Output:
|
||||
// [2 1 5 3 6 4]
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleHeapSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
HeapSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleMergeSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
MergeSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleInsertionSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
InsertionSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleSelectionSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
SelectionSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleShellSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
ShellSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
|
||||
func ExampleQuickSort() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
|
||||
QuickSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
@@ -66,6 +66,7 @@ func TestBubbleSortForStructSlice(t *testing.T) {
|
||||
|
||||
func TestBubbleSortForIntSlice(t *testing.T) {
|
||||
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
|
||||
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
BubbleSort(numbers, comparator)
|
||||
|
||||
@@ -11,17 +11,18 @@ import (
|
||||
|
||||
// Channel is a logic object which can generate or manipulate go channel
|
||||
// all methods of Channel are in the book tilted《Concurrency in Go》
|
||||
type Channel struct {
|
||||
type Channel[T any] struct {
|
||||
}
|
||||
|
||||
// NewChannel return a Channel instance
|
||||
func NewChannel() *Channel {
|
||||
return &Channel{}
|
||||
func NewChannel[T any]() *Channel[T] {
|
||||
return &Channel[T]{}
|
||||
}
|
||||
|
||||
// Generate a data of type any chan, put param `values` into the chan
|
||||
func (c *Channel) Generate(ctx context.Context, values ...any) <-chan any {
|
||||
dataStream := make(chan any)
|
||||
// Generate creates channel, then put values into the channel.
|
||||
// Play: https://go.dev/play/p/7aB4KyMMp9A
|
||||
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T {
|
||||
dataStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(dataStream)
|
||||
@@ -38,9 +39,10 @@ func (c *Channel) Generate(ctx context.Context, values ...any) <-chan any {
|
||||
return dataStream
|
||||
}
|
||||
|
||||
// Repeat return a data of type any chan, put param `values` into the chan repeatly until cancel the context.
|
||||
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any {
|
||||
dataStream := make(chan any)
|
||||
// Repeat create channel, put values into the channel repeatly until cancel the context.
|
||||
// Play: https://go.dev/play/p/k5N_ALVmYjE
|
||||
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T {
|
||||
dataStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(dataStream)
|
||||
@@ -57,10 +59,11 @@ func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any {
|
||||
return dataStream
|
||||
}
|
||||
|
||||
// RepeatFn return a chan, excutes fn repeatly, and put the result into retruned chan
|
||||
// until close the `done` channel
|
||||
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any {
|
||||
dataStream := make(chan any)
|
||||
// RepeatFn create a channel, excutes fn repeatly, and put the result into the channel
|
||||
// until close context.
|
||||
// Play: https://go.dev/play/p/4J1zAWttP85
|
||||
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T {
|
||||
dataStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(dataStream)
|
||||
@@ -75,9 +78,10 @@ func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any {
|
||||
return dataStream
|
||||
}
|
||||
|
||||
// Take return a chan whose values are tahken from another chan
|
||||
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any {
|
||||
takeStream := make(chan any)
|
||||
// Take create a channel whose values are taken from another channel with limit number.
|
||||
// Play: https://go.dev/play/p/9Utt-1pDr2J
|
||||
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T {
|
||||
takeStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(takeStream)
|
||||
@@ -94,16 +98,17 @@ func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int)
|
||||
return takeStream
|
||||
}
|
||||
|
||||
// FanIn merge multiple channels into one channel
|
||||
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any {
|
||||
out := make(chan any)
|
||||
// FanIn merge multiple channels into one channel.
|
||||
// Play: https://go.dev/play/p/2VYFMexEvTm
|
||||
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T {
|
||||
out := make(chan T)
|
||||
|
||||
go func() {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(channels))
|
||||
|
||||
for _, c := range channels {
|
||||
go func(c <-chan any) {
|
||||
go func(c <-chan T) {
|
||||
defer wg.Done()
|
||||
for v := range c {
|
||||
select {
|
||||
@@ -121,10 +126,11 @@ func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
|
||||
return out
|
||||
}
|
||||
|
||||
// Tee split one chanel into two channels
|
||||
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any) {
|
||||
out1 := make(chan any)
|
||||
out2 := make(chan any)
|
||||
// Tee split one chanel into two channels, until cancel the context.
|
||||
// Play: https://go.dev/play/p/3TQPKnCirrP
|
||||
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T) {
|
||||
out1 := make(chan T)
|
||||
out2 := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(out1)
|
||||
@@ -147,15 +153,16 @@ func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan an
|
||||
return out1, out2
|
||||
}
|
||||
|
||||
// Bridge link multiply channels into one channel
|
||||
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any {
|
||||
valStream := make(chan any)
|
||||
// Bridge link multiply channels into one channel.
|
||||
// Play: https://go.dev/play/p/qmWSy1NVF-Y
|
||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T {
|
||||
valStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(valStream)
|
||||
|
||||
for {
|
||||
var stream <-chan any
|
||||
var stream <-chan T
|
||||
select {
|
||||
case maybeStream, ok := <-chanStream:
|
||||
if !ok {
|
||||
@@ -178,8 +185,9 @@ func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-ch
|
||||
return valStream
|
||||
}
|
||||
|
||||
// Or read one or more channels into one channel, will close when any readin channel is closed
|
||||
func (c *Channel) Or(channels ...<-chan any) <-chan any {
|
||||
// Or read one or more channels into one channel, will close when any readin channel is closed.
|
||||
// Play: https://go.dev/play/p/Wqz9rwioPww
|
||||
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T {
|
||||
switch len(channels) {
|
||||
case 0:
|
||||
return nil
|
||||
@@ -187,7 +195,7 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
|
||||
return channels[0]
|
||||
}
|
||||
|
||||
orDone := make(chan any)
|
||||
orDone := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(orDone)
|
||||
@@ -199,17 +207,12 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
|
||||
case <-channels[1]:
|
||||
}
|
||||
default:
|
||||
m := len(channels) / 2
|
||||
select {
|
||||
case <-c.Or(channels[:m]...):
|
||||
case <-c.Or(channels[m:]...):
|
||||
case <-channels[0]:
|
||||
case <-channels[1]:
|
||||
case <-channels[2]:
|
||||
case <-c.Or(append(channels[3:], orDone)...):
|
||||
}
|
||||
// select {
|
||||
// case <-channels[0]:
|
||||
// case <-channels[1]:
|
||||
// case <-channels[2]:
|
||||
// case <-c.Or(append(channels[3:], orDone)...):
|
||||
// }
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -217,8 +220,9 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
|
||||
}
|
||||
|
||||
// OrDone read a channel into another channel, will close until cancel context.
|
||||
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any {
|
||||
valStream := make(chan any)
|
||||
// Play: https://go.dev/play/p/lm_GoS6aDjo
|
||||
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T {
|
||||
valStream := make(chan T)
|
||||
|
||||
go func() {
|
||||
defer close(valStream)
|
||||
|
||||
196
concurrency/channel_example_test.go
Normal file
196
concurrency/channel_example_test.go
Normal file
@@ -0,0 +1,196 @@
|
||||
package concurrency
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleChannel_Generate() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Generate(ctx, 1, 2, 3)
|
||||
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleChannel_Repeat() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleChannel_RepeatFn() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() string {
|
||||
return "hello"
|
||||
}
|
||||
|
||||
c := NewChannel[string]()
|
||||
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// hello
|
||||
// hello
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleChannel_Take() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan int, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
numbers <- 4
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleChannel_FanIn() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
channels := make([]<-chan int, 2)
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
|
||||
}
|
||||
|
||||
chs := c.FanIn(ctx, channels...)
|
||||
|
||||
for v := range chs {
|
||||
fmt.Println(v) //1 1 0 0 or 0 0 1 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func ExampleChannel_Or() {
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan any)
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
}()
|
||||
return c
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := NewChannel[any]()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
sig(3*time.Second),
|
||||
)
|
||||
|
||||
if time.Since(start).Seconds() < 2 {
|
||||
fmt.Println("ok")
|
||||
}
|
||||
// Output:
|
||||
// ok
|
||||
}
|
||||
|
||||
func ExampleChannel_OrDone() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
|
||||
for v := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleChannel_Tee() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
|
||||
|
||||
ch1, ch2 := c.Tee(ctx, intStream)
|
||||
|
||||
for v := range ch1 {
|
||||
fmt.Println(v)
|
||||
fmt.Println(<-ch2)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleChannel_Bridge() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
out := make(chan (<-chan int))
|
||||
go func() {
|
||||
defer close(out)
|
||||
for i := 1; i <= 5; i++ {
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
out <- stream
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
for v := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
// 4
|
||||
// 5
|
||||
}
|
||||
@@ -14,12 +14,9 @@ func TestGenerate(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Generate(ctx, 1, 2, 3)
|
||||
|
||||
// for v := range intStream {
|
||||
// t.Log(v) //1, 2, 3
|
||||
// }
|
||||
assert.Equal(1, <-intStream)
|
||||
assert.Equal(2, <-intStream)
|
||||
assert.Equal(3, <-intStream)
|
||||
@@ -31,12 +28,9 @@ func TestRepeat(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
|
||||
|
||||
// for v := range intStream {
|
||||
// t.Log(v) //1, 2, 1, 2, 1
|
||||
// }
|
||||
assert.Equal(1, <-intStream)
|
||||
assert.Equal(2, <-intStream)
|
||||
assert.Equal(1, <-intStream)
|
||||
@@ -50,17 +44,13 @@ func TestRepeatFn(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() any {
|
||||
fn := func() string {
|
||||
s := "a"
|
||||
return s
|
||||
}
|
||||
c := NewChannel()
|
||||
c := NewChannel[string]()
|
||||
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
// for v := range dataStream {
|
||||
// t.Log(v) //a, a, a
|
||||
// }
|
||||
|
||||
assert.Equal("a", <-dataStream)
|
||||
assert.Equal("a", <-dataStream)
|
||||
assert.Equal("a", <-dataStream)
|
||||
@@ -72,7 +62,7 @@ func TestTake(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan any, 5)
|
||||
numbers := make(chan int, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
@@ -80,7 +70,7 @@ func TestTake(t *testing.T) {
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
assert.Equal(1, <-intStream)
|
||||
@@ -94,8 +84,8 @@ func TestFanIn(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
channels := make([]<-chan any, 3)
|
||||
c := NewChannel[int]()
|
||||
channels := make([]<-chan int, 3)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
||||
@@ -124,7 +114,7 @@ func TestOr(t *testing.T) {
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[any]()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
@@ -133,9 +123,7 @@ func TestOr(t *testing.T) {
|
||||
sig(5*time.Second),
|
||||
)
|
||||
|
||||
t.Logf("done after %v", time.Since(start))
|
||||
|
||||
assert.Equal(1, 1)
|
||||
assert.Equal(true, time.Since(start).Seconds() < 2)
|
||||
}
|
||||
|
||||
func TestOrDone(t *testing.T) {
|
||||
@@ -144,16 +132,12 @@ func TestOrDone(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
|
||||
var res any
|
||||
for val := range c.OrDone(ctx, intStream) {
|
||||
t.Logf("%v", val)
|
||||
res = val
|
||||
assert.Equal(1, val)
|
||||
}
|
||||
|
||||
assert.Equal(1, res)
|
||||
}
|
||||
|
||||
func TestTee(t *testing.T) {
|
||||
@@ -162,15 +146,13 @@ func TestTee(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
c := NewChannel[int]()
|
||||
inStream := c.Take(ctx, c.Repeat(ctx, 1), 4)
|
||||
|
||||
out1, out2 := c.Tee(ctx, inStream)
|
||||
for val := range out1 {
|
||||
val1 := val
|
||||
val2 := <-out2
|
||||
// t.Log("val1 is", val1)
|
||||
// t.Log("val2 is", val2)
|
||||
assert.Equal(1, val1)
|
||||
assert.Equal(1, val2)
|
||||
}
|
||||
@@ -182,13 +164,13 @@ func TestBridge(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := NewChannel()
|
||||
genVals := func() <-chan <-chan any {
|
||||
chanStream := make(chan (<-chan any))
|
||||
c := NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
chanStream := make(chan (<-chan int))
|
||||
go func() {
|
||||
defer close(chanStream)
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan any, 1)
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
|
||||
@@ -13,6 +13,7 @@ import "reflect"
|
||||
// If the type has an IsZero() bool method, the opposite value is returned.
|
||||
// Slices and maps are truthy if they have a length greater than zero.
|
||||
// All other types are truthy if they are not their zero value.
|
||||
// Play: https://go.dev/play/p/ETzeDJRSvhm
|
||||
func Bool[T any](value T) bool {
|
||||
switch m := any(value).(type) {
|
||||
case interface{ Bool() bool }:
|
||||
@@ -34,40 +35,47 @@ func reflectValue(vp any) bool {
|
||||
}
|
||||
|
||||
// And returns true if both a and b are truthy.
|
||||
// Play: https://go.dev/play/p/W1SSUmt6pvr
|
||||
func And[T, U any](a T, b U) bool {
|
||||
return Bool(a) && Bool(b)
|
||||
}
|
||||
|
||||
// Or returns false iff neither a nor b is truthy.
|
||||
// Or returns false if neither a nor b is truthy.
|
||||
// Play: https://go.dev/play/p/UlQTxHaeEkq
|
||||
func Or[T, U any](a T, b U) bool {
|
||||
return Bool(a) || Bool(b)
|
||||
}
|
||||
|
||||
// Xor returns true iff a or b but not both is truthy.
|
||||
// Xor returns true if a or b but not both is truthy.
|
||||
// Play: https://go.dev/play/p/gObZrW7ZbG8
|
||||
func Xor[T, U any](a T, b U) bool {
|
||||
valA := Bool(a)
|
||||
valB := Bool(b)
|
||||
return (valA || valB) && valA != valB
|
||||
}
|
||||
|
||||
// Nor returns true iff neither a nor b is truthy.
|
||||
// Nor returns true if neither a nor b is truthy.
|
||||
// Play: https://go.dev/play/p/g2j08F_zZky
|
||||
func Nor[T, U any](a T, b U) bool {
|
||||
return !(Bool(a) || Bool(b))
|
||||
}
|
||||
|
||||
// Xnor returns true iff both a and b or neither a nor b are truthy.
|
||||
// Xnor returns true if both a and b or neither a nor b are truthy.
|
||||
// Play: https://go.dev/play/p/OuDB9g51643
|
||||
func Xnor[T, U any](a T, b U) bool {
|
||||
valA := Bool(a)
|
||||
valB := Bool(b)
|
||||
return (valA && valB) || (!valA && !valB)
|
||||
}
|
||||
|
||||
// Nand returns false iff both a and b are truthy.
|
||||
// Nand returns false if both a and b are truthy.
|
||||
// Play: https://go.dev/play/p/vSRMLxLIbq8
|
||||
func Nand[T, U any](a T, b U) bool {
|
||||
return !Bool(a) || !Bool(b)
|
||||
}
|
||||
|
||||
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue
|
||||
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue.
|
||||
// Play: https://go.dev/play/p/ElllPZY0guT
|
||||
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||
if Bool(isTrue) {
|
||||
return ifValue
|
||||
|
||||
163
condition/condition_example_test.go
Normal file
163
condition/condition_example_test.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package condition
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleBool() {
|
||||
// bool
|
||||
result1 := Bool(false)
|
||||
result2 := Bool(true)
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// integer
|
||||
result3 := Bool(0)
|
||||
result4 := Bool(1)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// string
|
||||
result5 := Bool("")
|
||||
result6 := Bool(" ")
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// slice
|
||||
var nums = []int{}
|
||||
result7 := Bool(nums)
|
||||
nums = append(nums, 1, 2)
|
||||
result8 := Bool(nums)
|
||||
fmt.Println(result7)
|
||||
fmt.Println(result8)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleAnd() {
|
||||
result1 := And(0, 1)
|
||||
result2 := And(0, "")
|
||||
result3 := And(0, "0")
|
||||
result4 := And(1, "0")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleOr() {
|
||||
result1 := Or(0, "")
|
||||
result2 := Or(0, 1)
|
||||
result3 := Or(0, "0")
|
||||
result4 := Or(1, "0")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleXor() {
|
||||
result1 := Xor(0, 0)
|
||||
result2 := Xor(1, 1)
|
||||
result3 := Xor(0, 1)
|
||||
result4 := Xor(1, 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleNor() {
|
||||
result1 := Nor(0, 0)
|
||||
result2 := Nor(1, 1)
|
||||
result3 := Nor(0, 1)
|
||||
result4 := Nor(1, 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleXnor() {
|
||||
result1 := Xnor(0, 0)
|
||||
result2 := Xnor(1, 1)
|
||||
result3 := Xnor(0, 1)
|
||||
result4 := Xnor(1, 0)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleNand() {
|
||||
result1 := Nand(0, 0)
|
||||
result2 := Nand(1, 0)
|
||||
result3 := Nand(0, 1)
|
||||
result4 := Nand(1, 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleTernaryOperator() {
|
||||
conditionTrue := 2 > 1
|
||||
result1 := TernaryOperator(conditionTrue, 0, 1)
|
||||
fmt.Println(result1)
|
||||
|
||||
conditionFalse := 2 > 3
|
||||
result2 := TernaryOperator(conditionFalse, 0, 1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
@@ -17,12 +17,14 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ToBool convert string to a boolean
|
||||
// ToBool convert string to boolean.
|
||||
// Play: https://go.dev/play/p/ARht2WnGdIN
|
||||
func ToBool(s string) (bool, error) {
|
||||
return strconv.ParseBool(s)
|
||||
}
|
||||
|
||||
// ToBytes convert interface to bytes
|
||||
// ToBytes convert value to byte slice.
|
||||
// Play: https://go.dev/play/p/fAMXYFDvOvr
|
||||
func ToBytes(value any) ([]byte, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
@@ -63,7 +65,8 @@ func ToBytes(value any) ([]byte, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// ToChar convert string to char slice
|
||||
// ToChar convert string to char slice.
|
||||
// Play: https://go.dev/play/p/JJ1SvbFkVdM
|
||||
func ToChar(s string) []string {
|
||||
c := make([]string, 0)
|
||||
if len(s) == 0 {
|
||||
@@ -75,7 +78,8 @@ func ToChar(s string) []string {
|
||||
return c
|
||||
}
|
||||
|
||||
// ToChannel convert a array of elements to a read-only channels
|
||||
// ToChannel convert a slice of elements to a read-only channel.
|
||||
// Play: https://go.dev/play/p/hOx_oYZbAnL
|
||||
func ToChannel[T any](array []T) <-chan T {
|
||||
ch := make(chan T)
|
||||
|
||||
@@ -91,7 +95,8 @@ func ToChannel[T any](array []T) <-chan T {
|
||||
|
||||
// ToString convert value to string
|
||||
// for number, string, []byte, will convert to string
|
||||
// for other type (slice, map, array, struct) will call json.Marshal
|
||||
// for other type (slice, map, array, struct) will call json.Marshal.
|
||||
// Play: https://go.dev/play/p/nF1zOOslpQq
|
||||
func ToString(value any) string {
|
||||
if value == nil {
|
||||
return ""
|
||||
@@ -140,7 +145,8 @@ func ToString(value any) string {
|
||||
}
|
||||
}
|
||||
|
||||
// ToJson convert value to a valid json string
|
||||
// ToJson convert value to a json string.
|
||||
// Play: https://go.dev/play/p/2rLIkMmXWvR
|
||||
func ToJson(value any) (string, error) {
|
||||
result, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
@@ -150,7 +156,8 @@ func ToJson(value any) (string, error) {
|
||||
return string(result), nil
|
||||
}
|
||||
|
||||
// ToFloat convert value to a float64, if input is not a float return 0.0 and error
|
||||
// ToFloat convert value to float64, if input is not a float return 0.0 and error.
|
||||
// Play: https://go.dev/play/p/4YTmPCibqHJ
|
||||
func ToFloat(value any) (float64, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
@@ -177,12 +184,13 @@ func ToFloat(value any) (float64, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// ToInt convert value to a int64, if input is not a numeric format return 0 and error
|
||||
// ToInt convert value to int64 value, if input is not numerical, return 0 and error.
|
||||
// Play: https://go.dev/play/p/9_h9vIt-QZ_b
|
||||
func ToInt(value any) (int64, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
var result int64
|
||||
err := fmt.Errorf("ToInt: invalid interface type %T", value)
|
||||
err := fmt.Errorf("ToInt: invalid value type %T", value)
|
||||
switch value.(type) {
|
||||
case int, int8, int16, int32, int64:
|
||||
result = v.Int()
|
||||
@@ -204,12 +212,14 @@ func ToInt(value any) (int64, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// ToPointer returns a pointer to this value
|
||||
// ToPointer returns a pointer to passed value.
|
||||
// Play: https://go.dev/play/p/ASf_etHNlw1
|
||||
func ToPointer[T any](value T) *T {
|
||||
return &value
|
||||
}
|
||||
|
||||
// ToMap convert a slice or an array of structs to a map based on iteratee function
|
||||
// ToMap convert a slice of structs to a map based on iteratee function.
|
||||
// Play: https://go.dev/play/p/tVFy7E-t24l
|
||||
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V {
|
||||
result := make(map[K]V, len(array))
|
||||
for _, item := range array {
|
||||
@@ -221,7 +231,8 @@ func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K
|
||||
}
|
||||
|
||||
// StructToMap convert struct to map, only convert exported struct field
|
||||
// map key is specified same as struct field tag `json` value
|
||||
// map key is specified same as struct field tag `json` value.
|
||||
// Play: https://go.dev/play/p/KYGYJqNUBOI
|
||||
func StructToMap(value any) (map[string]any, error) {
|
||||
v := reflect.ValueOf(value)
|
||||
t := reflect.TypeOf(value)
|
||||
@@ -250,7 +261,8 @@ func StructToMap(value any) (map[string]any, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// MapToSlice convert a map to a slice based on iteratee function
|
||||
// MapToSlice convert map to slice based on iteratee function.
|
||||
// Play: https://go.dev/play/p/dmX4Ix5V6Wl
|
||||
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T {
|
||||
result := make([]T, 0, len(aMap))
|
||||
|
||||
@@ -261,7 +273,8 @@ func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T)
|
||||
return result
|
||||
}
|
||||
|
||||
// ColorHexToRGB convert hex color to rgb color
|
||||
// ColorHexToRGB convert hex color to rgb color.
|
||||
// Play: https://go.dev/play/p/o7_ft-JCJBV
|
||||
func ColorHexToRGB(colorHex string) (red, green, blue int) {
|
||||
colorHex = strings.TrimPrefix(colorHex, "#")
|
||||
color64, err := strconv.ParseInt(colorHex, 16, 32)
|
||||
@@ -272,7 +285,8 @@ func ColorHexToRGB(colorHex string) (red, green, blue int) {
|
||||
return color >> 16, (color & 0x00FF00) >> 8, color & 0x0000FF
|
||||
}
|
||||
|
||||
// ColorRGBToHex convert rgb color to hex color
|
||||
// ColorRGBToHex convert rgb color to hex color.
|
||||
// Play: https://go.dev/play/p/nzKS2Ro87J1
|
||||
func ColorRGBToHex(red, green, blue int) string {
|
||||
r := strconv.FormatInt(int64(red), 16)
|
||||
g := strconv.FormatInt(int64(green), 16)
|
||||
@@ -291,7 +305,8 @@ func ColorRGBToHex(red, green, blue int) string {
|
||||
return "#" + r + g + b
|
||||
}
|
||||
|
||||
// EncodeByte encode data to byte
|
||||
// EncodeByte encode data to byte slice.
|
||||
// Play: https://go.dev/play/p/DVmM1G5JfuP
|
||||
func EncodeByte(data any) ([]byte, error) {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
encoder := gob.NewEncoder(buffer)
|
||||
@@ -302,7 +317,8 @@ func EncodeByte(data any) ([]byte, error) {
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
// DecodeByte decode byte data to target object
|
||||
// DecodeByte decode byte slice data to target object.
|
||||
// Play: https://go.dev/play/p/zI6xsmuQRbn
|
||||
func DecodeByte(data []byte, target any) error {
|
||||
buffer := bytes.NewBuffer(data)
|
||||
decoder := gob.NewDecoder(buffer)
|
||||
|
||||
254
convertor/convertor_example_test.go
Normal file
254
convertor/convertor_example_test.go
Normal file
@@ -0,0 +1,254 @@
|
||||
package convertor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func ExampleToBool() {
|
||||
cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
|
||||
|
||||
for i := 0; i < len(cases); i++ {
|
||||
result, _ := ToBool(cases[i])
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleToBytes() {
|
||||
result1, _ := ToBytes(1)
|
||||
result2, _ := ToBytes("abc")
|
||||
result3, _ := ToBytes(true)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// [0 0 0 0 0 0 0 1]
|
||||
// [97 98 99]
|
||||
// [116 114 117 101]
|
||||
}
|
||||
|
||||
func ExampleToChar() {
|
||||
result1 := ToChar("")
|
||||
result2 := ToChar("abc")
|
||||
result3 := ToChar("1 2#3")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// []
|
||||
// [a b c]
|
||||
// [1 2 # 3]
|
||||
}
|
||||
|
||||
func ExampleToChannel() {
|
||||
ch := ToChannel([]int{1, 2, 3})
|
||||
result1 := <-ch
|
||||
result2 := <-ch
|
||||
result3 := <-ch
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleToString() {
|
||||
result1 := ToString("")
|
||||
result2 := ToString(nil)
|
||||
result3 := ToString(0)
|
||||
result4 := ToString(1.23)
|
||||
result5 := ToString(true)
|
||||
result6 := ToString(false)
|
||||
result7 := ToString([]int{1, 2, 3})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
//
|
||||
//
|
||||
// 0
|
||||
// 1.23
|
||||
// true
|
||||
// false
|
||||
// [1,2,3]
|
||||
}
|
||||
|
||||
func ExampleToJson() {
|
||||
|
||||
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
result1, err := ToJson(aMap)
|
||||
if err != nil {
|
||||
fmt.Printf("%v", err)
|
||||
}
|
||||
fmt.Println(result1)
|
||||
|
||||
// Output:
|
||||
// {"a":1,"b":2,"c":3}
|
||||
}
|
||||
|
||||
func ExampleToFloat() {
|
||||
result1, _ := ToFloat("")
|
||||
result2, _ := ToFloat("abc")
|
||||
result3, _ := ToFloat("-1")
|
||||
result4, _ := ToFloat("-.11")
|
||||
result5, _ := ToFloat("1.23e3")
|
||||
result6, _ := ToFloat(true)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 0
|
||||
// -1
|
||||
// -0.11
|
||||
// 1230
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleToInt() {
|
||||
result1, _ := ToInt("123")
|
||||
result2, _ := ToInt("-123")
|
||||
result3, _ := ToInt(float64(12.3))
|
||||
result4, _ := ToInt("abc")
|
||||
result5, _ := ToInt(true)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// -123
|
||||
// 12
|
||||
// 0
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleToPointer() {
|
||||
result := ToPointer(123)
|
||||
fmt.Println(*result)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
}
|
||||
|
||||
func ExampleToMap() {
|
||||
type Message struct {
|
||||
name string
|
||||
code int
|
||||
}
|
||||
messages := []Message{
|
||||
{name: "Hello", code: 100},
|
||||
{name: "Hi", code: 101},
|
||||
}
|
||||
result := ToMap(messages, func(msg Message) (int, string) {
|
||||
return msg.code, msg.name
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[100:Hello 101:Hi]
|
||||
}
|
||||
|
||||
func ExampleStructToMap() {
|
||||
type People struct {
|
||||
Name string `json:"name"`
|
||||
age int
|
||||
}
|
||||
p := People{
|
||||
"test",
|
||||
100,
|
||||
}
|
||||
pm, _ := StructToMap(p)
|
||||
|
||||
fmt.Println(pm)
|
||||
|
||||
// Output:
|
||||
// map[name:test]
|
||||
}
|
||||
|
||||
func ExampleMapToSlice() {
|
||||
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
result := MapToSlice(aMap, func(key string, value int) string {
|
||||
return key + ":" + strconv.Itoa(value)
|
||||
})
|
||||
|
||||
fmt.Println(result) //[]string{"a:1", "c:3", "b:2"} (random order)
|
||||
}
|
||||
|
||||
func ExampleColorHexToRGB() {
|
||||
colorHex := "#003366"
|
||||
r, g, b := ColorHexToRGB(colorHex)
|
||||
|
||||
fmt.Println(r, g, b)
|
||||
|
||||
// Output:
|
||||
// 0 51 102
|
||||
}
|
||||
|
||||
func ExampleColorRGBToHex() {
|
||||
r := 0
|
||||
g := 51
|
||||
b := 102
|
||||
colorHex := ColorRGBToHex(r, g, b)
|
||||
|
||||
fmt.Println(colorHex)
|
||||
|
||||
// Output:
|
||||
// #003366
|
||||
}
|
||||
|
||||
func ExampleEncodeByte() {
|
||||
byteData, _ := EncodeByte("abc")
|
||||
fmt.Println(byteData)
|
||||
|
||||
// Output:
|
||||
// [6 12 0 3 97 98 99]
|
||||
}
|
||||
|
||||
func ExampleDecodeByte() {
|
||||
var obj string
|
||||
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||
err := DecodeByte(byteData, &obj)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(obj)
|
||||
|
||||
// Output:
|
||||
// abc
|
||||
}
|
||||
186
cryptor/aes.go
186
cryptor/aes.go
@@ -1,186 +0,0 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package cryptor implements some util functions to encrypt and decrypt.
|
||||
// Note:
|
||||
// 1. for aes crypt function, the `key` param length should be 16, 24 or 32. if not, will panic.
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
)
|
||||
|
||||
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesEcbEncrypt(data, key []byte) []byte {
|
||||
length := (len(data) + aes.BlockSize) / aes.BlockSize
|
||||
plain := make([]byte, length*aes.BlockSize)
|
||||
|
||||
copy(plain, data)
|
||||
|
||||
pad := byte(len(plain) - len(data))
|
||||
for i := len(data); i < len(plain); i++ {
|
||||
plain[i] = pad
|
||||
}
|
||||
|
||||
encrypted := make([]byte, len(plain))
|
||||
cipher, _ := aes.NewCipher(generateAesKey(key))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||
}
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesEcbDecrypt decrypt data with key use AES ECB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesEcbDecrypt(encrypted, key []byte) []byte {
|
||||
cipher, _ := aes.NewCipher(generateAesKey(key))
|
||||
decrypted := make([]byte, len(encrypted))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
|
||||
}
|
||||
|
||||
trim := 0
|
||||
if len(decrypted) > 0 {
|
||||
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
|
||||
}
|
||||
|
||||
return decrypted[:trim]
|
||||
}
|
||||
|
||||
// AesCbcEncrypt encrypt data with key use AES CBC algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesCbcEncrypt(data, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
data = pkcs7Padding(data, block.BlockSize())
|
||||
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(encrypted[aes.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesCbcDecrypt decrypt data with key use AES CBC algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesCbcDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
encrypted = encrypted[aes.BlockSize:]
|
||||
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(encrypted, encrypted)
|
||||
|
||||
decrypted := pkcs7UnPadding(encrypted)
|
||||
return decrypted
|
||||
}
|
||||
|
||||
// AesCtrCrypt encrypt data with key use AES CTR algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesCtrCrypt(data, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
|
||||
iv := bytes.Repeat([]byte("1"), block.BlockSize())
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
|
||||
dst := make([]byte, len(data))
|
||||
stream.XORKeyStream(dst, data)
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// AesCfbEncrypt encrypt data with key use AES CFB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesCfbEncrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesCfbDecrypt decrypt data with key use AES CFB algorithm
|
||||
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32
|
||||
func AesCfbDecrypt(encrypted, key []byte) []byte {
|
||||
if len(encrypted) < aes.BlockSize {
|
||||
panic("encrypted data is too short")
|
||||
}
|
||||
|
||||
block, _ := aes.NewCipher(key)
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
encrypted = encrypted[aes.BlockSize:]
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
|
||||
stream.XORKeyStream(encrypted, encrypted)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesOfbEncrypt encrypt data with key use AES OFB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesOfbEncrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
data = pkcs7Padding(data, aes.BlockSize)
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesOfbDecrypt decrypt data with key use AES OFB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func AesOfbDecrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
iv := data[:aes.BlockSize]
|
||||
data = data[aes.BlockSize:]
|
||||
if len(data)%aes.BlockSize != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
decrypted := make([]byte, len(data))
|
||||
mode := cipher.NewOFB(block, iv)
|
||||
mode.XORKeyStream(decrypted, data)
|
||||
|
||||
decrypted = pkcs7UnPadding(decrypted)
|
||||
|
||||
return decrypted
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestAesEcbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesEcbEncrypt := AesEcbEncrypt([]byte(data), []byte(key))
|
||||
aesEcbDecrypt := AesEcbDecrypt(aesEcbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesEcbEncrypt")
|
||||
assert.Equal(data, string(aesEcbDecrypt))
|
||||
}
|
||||
|
||||
func TestAesCbcEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesCbcEncrypt := AesCbcEncrypt([]byte(data), []byte(key))
|
||||
aesCbcDecrypt := AesCbcDecrypt(aesCbcEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesCbcEncrypt")
|
||||
assert.Equal(data, string(aesCbcDecrypt))
|
||||
}
|
||||
|
||||
func TestAesCtrCrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesCtrCrypt := AesCtrCrypt([]byte(data), []byte(key))
|
||||
aesCtrDeCrypt := AesCtrCrypt(aesCtrCrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesCtrCrypt")
|
||||
assert.Equal(data, string(aesCtrDeCrypt))
|
||||
}
|
||||
|
||||
func TestAesCfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesCfbEncrypt := AesCfbEncrypt([]byte(data), []byte(key))
|
||||
aesCfbDecrypt := AesCfbDecrypt(aesCfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesCfbEncrypt")
|
||||
assert.Equal(data, string(aesCfbDecrypt))
|
||||
}
|
||||
|
||||
func TestAesOfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesOfbEncrypt := AesOfbEncrypt([]byte(data), []byte(key))
|
||||
aesOfbDecrypt := AesOfbDecrypt(aesOfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesOfbEncrypt")
|
||||
assert.Equal(data, string(aesOfbDecrypt))
|
||||
}
|
||||
@@ -19,25 +19,28 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// Base64StdEncode encode string with base64 encoding
|
||||
// Base64StdEncode encode string with base64 encoding.
|
||||
// Play: https://go.dev/play/p/VOaUyQUreoK
|
||||
func Base64StdEncode(s string) string {
|
||||
return base64.StdEncoding.EncodeToString([]byte(s))
|
||||
}
|
||||
|
||||
// Base64StdDecode decode a base64 encoded string
|
||||
// Base64StdDecode decode a base64 encoded string.
|
||||
// Play: https://go.dev/play/p/RWQylnJVgIe
|
||||
func Base64StdDecode(s string) string {
|
||||
b, _ := base64.StdEncoding.DecodeString(s)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// Md5String return the md5 value of string
|
||||
// Md5String return the md5 value of string.
|
||||
// Play: https://go.dev/play/p/1bLcVetbTOI
|
||||
func Md5String(s string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(s))
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// Md5File return the md5 value of file
|
||||
// Md5File return the md5 value of file.
|
||||
func Md5File(filename string) (string, error) {
|
||||
if fileInfo, err := os.Stat(filename); err != nil {
|
||||
return "", err
|
||||
@@ -69,49 +72,56 @@ func Md5File(filename string) (string, error) {
|
||||
return checksum, nil
|
||||
}
|
||||
|
||||
// HmacMd5 return the hmac hash of string use md5
|
||||
// HmacMd5 return the hmac hash of string use md5.
|
||||
// Play: https://go.dev/play/p/uef0q1fz53I
|
||||
func HmacMd5(data, key string) string {
|
||||
h := hmac.New(md5.New, []byte(key))
|
||||
h.Write([]byte(data))
|
||||
return hex.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacSha1 return the hmac hash of string use sha1
|
||||
// HmacSha1 return the hmac hash of string use sha1.
|
||||
// Play: https://go.dev/play/p/1UI4oQ4WXKM
|
||||
func HmacSha1(data, key string) string {
|
||||
h := hmac.New(sha1.New, []byte(key))
|
||||
h.Write([]byte(data))
|
||||
return hex.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacSha256 return the hmac hash of string use sha256
|
||||
// HmacSha256 return the hmac hash of string use sha256.
|
||||
// Play: https://go.dev/play/p/HhpwXxFhhC0
|
||||
func HmacSha256(data, key string) string {
|
||||
h := hmac.New(sha256.New, []byte(key))
|
||||
h.Write([]byte(data))
|
||||
return hex.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// HmacSha512 return the hmac hash of string use sha512
|
||||
// HmacSha512 return the hmac hash of string use sha512.
|
||||
// Play: https://go.dev/play/p/59Od6m4A0Ud
|
||||
func HmacSha512(data, key string) string {
|
||||
h := hmac.New(sha512.New, []byte(key))
|
||||
h.Write([]byte(data))
|
||||
return hex.EncodeToString(h.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// Sha1 return the sha1 value (SHA-1 hash algorithm) of string
|
||||
// Sha1 return the sha1 value (SHA-1 hash algorithm) of string.
|
||||
// Play: https://go.dev/play/p/_m_uoD1deMT
|
||||
func Sha1(data string) string {
|
||||
sha1 := sha1.New()
|
||||
sha1.Write([]byte(data))
|
||||
return hex.EncodeToString(sha1.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// Sha256 return the sha256 value (SHA256 hash algorithm) of string
|
||||
// Sha256 return the sha256 value (SHA256 hash algorithm) of string.
|
||||
// Play: https://go.dev/play/p/tU9tfBMIAr1
|
||||
func Sha256(data string) string {
|
||||
sha256 := sha256.New()
|
||||
sha256.Write([]byte(data))
|
||||
return hex.EncodeToString(sha256.Sum([]byte("")))
|
||||
}
|
||||
|
||||
// Sha512 return the sha512 value (SHA512 hash algorithm) of string
|
||||
// Sha512 return the sha512 value (SHA512 hash algorithm) of string.
|
||||
// Play: https://go.dev/play/p/3WsvLYZxsHa
|
||||
func Sha512(data string) string {
|
||||
sha512 := sha512.New()
|
||||
sha512.Write([]byte(data))
|
||||
|
||||
410
cryptor/crypto_example_test.go
Normal file
410
cryptor/crypto_example_test.go
Normal file
@@ -0,0 +1,410 @@
|
||||
package cryptor
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleAesEcbEncrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := AesEcbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := AesEcbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleAesEcbDecrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := AesEcbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := AesEcbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleAesCbcEncrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := AesCbcEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := AesCbcDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleAesCbcDecrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := AesCbcEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := AesCbcDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleAesCtrCrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := AesCtrCrypt([]byte(data), []byte(key))
|
||||
decrypted := AesCtrCrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleAesCfbEncrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := AesCfbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := AesCfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleAesCfbDecrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := AesCfbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := AesCfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleAesOfbEncrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := AesOfbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := AesOfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleAesOfbDecrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := AesOfbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := AesOfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleDesEcbEncrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
|
||||
encrypted := DesEcbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := DesEcbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleDesEcbDecrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
|
||||
encrypted := DesEcbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := DesEcbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleDesCbcEncrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
|
||||
encrypted := DesCbcEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := DesCbcDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleDesCbcDecrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
|
||||
encrypted := DesCbcEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := DesCbcDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleDesCtrCrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
|
||||
encrypted := DesCtrCrypt([]byte(data), []byte(key))
|
||||
decrypted := DesCtrCrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleDesCfbEncrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
|
||||
encrypted := DesCfbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := DesCfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleDesCfbDecrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
|
||||
encrypted := DesCfbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := DesCfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleDesOfbEncrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
|
||||
encrypted := DesOfbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := DesOfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleDesOfbDecrypt() {
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
|
||||
encrypted := DesOfbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := DesOfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleGenerateRsaKey() {
|
||||
// Create ras private and public pem file
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("foo")
|
||||
|
||||
// Output:
|
||||
// foo
|
||||
}
|
||||
|
||||
func ExampleRsaEncrypt() {
|
||||
// Create ras private and public pem file
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data := []byte("hello")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleRsaDecrypt() {
|
||||
// Create ras private and public pem file
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data := []byte("hello")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleBase64StdEncode() {
|
||||
base64Str := Base64StdEncode("hello")
|
||||
|
||||
fmt.Println(base64Str)
|
||||
|
||||
// Output:
|
||||
// aGVsbG8=
|
||||
}
|
||||
|
||||
func ExampleBase64StdDecode() {
|
||||
str := Base64StdDecode("aGVsbG8=")
|
||||
|
||||
fmt.Println(str)
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleHmacMd5() {
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := HmacMd5(str, key)
|
||||
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// e834306eab892d872525d4918a7a639a
|
||||
}
|
||||
|
||||
func ExampleHmacSha1() {
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := HmacSha1(str, key)
|
||||
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// 5c6a9db0cccb92e36ed0323fd09b7f936de9ace0
|
||||
}
|
||||
|
||||
func ExampleHmacSha256() {
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := HmacSha256(str, key)
|
||||
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// 315bb93c4e989862ba09cb62e05d73a5f376cb36f0d786edab0c320d059fde75
|
||||
}
|
||||
|
||||
func ExampleHmacSha512() {
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := HmacSha512(str, key)
|
||||
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// dd8f1290a9dd23d354e2526d9a2e9ce8cffffdd37cb320800d1c6c13d2efc363288376a196c5458daf53f8e1aa6b45a6d856303d5c0a2064bff9785861d48cfc
|
||||
}
|
||||
|
||||
func ExampleMd5String() {
|
||||
str := "hello"
|
||||
|
||||
md5Str := Md5String(str)
|
||||
|
||||
fmt.Println(md5Str)
|
||||
|
||||
// Output:
|
||||
// 5d41402abc4b2a76b9719d911017c592
|
||||
}
|
||||
|
||||
func ExampleSha1() {
|
||||
str := "hello"
|
||||
|
||||
result := Sha1(str)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
|
||||
}
|
||||
|
||||
func ExampleSha256() {
|
||||
str := "hello"
|
||||
|
||||
result := Sha256(str)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
|
||||
}
|
||||
|
||||
func ExampleSha512() {
|
||||
str := "hello"
|
||||
|
||||
result := Sha512(str)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
|
||||
}
|
||||
180
cryptor/des.go
180
cryptor/des.go
@@ -1,180 +0,0 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package cryptor implements some util functions to encrypt and decrypt.
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/rand"
|
||||
"io"
|
||||
)
|
||||
|
||||
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
|
||||
// len(key) should be 8
|
||||
func DesEcbEncrypt(data, key []byte) []byte {
|
||||
length := (len(data) + des.BlockSize) / des.BlockSize
|
||||
plain := make([]byte, length*des.BlockSize)
|
||||
copy(plain, data)
|
||||
|
||||
pad := byte(len(plain) - len(data))
|
||||
for i := len(data); i < len(plain); i++ {
|
||||
plain[i] = pad
|
||||
}
|
||||
|
||||
encrypted := make([]byte, len(plain))
|
||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||
}
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesEcbDecrypt decrypt data with key use DES ECB algorithm
|
||||
// len(key) should be 8
|
||||
func DesEcbDecrypt(encrypted, key []byte) []byte {
|
||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||
decrypted := make([]byte, len(encrypted))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
|
||||
}
|
||||
|
||||
trim := 0
|
||||
if len(decrypted) > 0 {
|
||||
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
|
||||
}
|
||||
|
||||
return decrypted[:trim]
|
||||
}
|
||||
|
||||
// DesCbcEncrypt encrypt data with key use DES CBC algorithm
|
||||
// len(key) should be 8
|
||||
func DesCbcEncrypt(data, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
data = pkcs7Padding(data, block.BlockSize())
|
||||
|
||||
encrypted := make([]byte, des.BlockSize+len(data))
|
||||
iv := encrypted[:des.BlockSize]
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(encrypted[des.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesCbcDecrypt decrypt data with key use DES CBC algorithm
|
||||
// len(key) should be 8
|
||||
func DesCbcDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
|
||||
iv := encrypted[:des.BlockSize]
|
||||
encrypted = encrypted[des.BlockSize:]
|
||||
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(encrypted, encrypted)
|
||||
|
||||
decrypted := pkcs7UnPadding(encrypted)
|
||||
return decrypted
|
||||
}
|
||||
|
||||
// DesCtrCrypt encrypt data with key use DES CTR algorithm
|
||||
// len(key) should be 8
|
||||
func DesCtrCrypt(data, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
|
||||
iv := bytes.Repeat([]byte("1"), block.BlockSize())
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
|
||||
dst := make([]byte, len(data))
|
||||
stream.XORKeyStream(dst, data)
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// DesCfbEncrypt encrypt data with key use DES CFB algorithm
|
||||
// len(key) should be 8
|
||||
func DesCfbEncrypt(data, key []byte) []byte {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
encrypted := make([]byte, des.BlockSize+len(data))
|
||||
iv := encrypted[:des.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted[des.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesCfbDecrypt decrypt data with key use DES CFB algorithm
|
||||
// len(encrypted) should be great than 16, len(key) should be 8
|
||||
func DesCfbDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
if len(encrypted) < des.BlockSize {
|
||||
panic("encrypted data is too short")
|
||||
}
|
||||
iv := encrypted[:des.BlockSize]
|
||||
encrypted = encrypted[des.BlockSize:]
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted, encrypted)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesOfbEncrypt encrypt data with key use DES OFB algorithm
|
||||
// len(key) should be 16, 24 or 32
|
||||
func DesOfbEncrypt(data, key []byte) []byte {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
data = pkcs7Padding(data, des.BlockSize)
|
||||
encrypted := make([]byte, des.BlockSize+len(data))
|
||||
iv := encrypted[:des.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(encrypted[des.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesOfbDecrypt decrypt data with key use DES OFB algorithm
|
||||
// len(key) should be 8
|
||||
func DesOfbDecrypt(data, key []byte) []byte {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
iv := data[:des.BlockSize]
|
||||
data = data[des.BlockSize:]
|
||||
if len(data)%des.BlockSize != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
decrypted := make([]byte, len(data))
|
||||
mode := cipher.NewOFB(block, iv)
|
||||
mode.XORKeyStream(decrypted, data)
|
||||
|
||||
decrypted = pkcs7UnPadding(decrypted)
|
||||
|
||||
return decrypted
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestDesEcbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desEcbEncrypt := DesEcbEncrypt([]byte(data), []byte(key))
|
||||
desEcbDecrypt := DesEcbDecrypt(desEcbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesEcbEncrypt")
|
||||
assert.Equal(data, string(desEcbDecrypt))
|
||||
}
|
||||
|
||||
func TestDesCbcEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desCbcEncrypt := DesCbcEncrypt([]byte(data), []byte(key))
|
||||
desCbcDecrypt := DesCbcDecrypt(desCbcEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesCbcEncrypt")
|
||||
assert.Equal(data, string(desCbcDecrypt))
|
||||
}
|
||||
|
||||
func TestDesCtrCrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desCtrCrypt := DesCtrCrypt([]byte(data), []byte(key))
|
||||
desCtrDeCrypt := DesCtrCrypt(desCtrCrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesCtrCrypt")
|
||||
assert.Equal(data, string(desCtrDeCrypt))
|
||||
}
|
||||
|
||||
func TestDesCfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desCfbEncrypt := DesCfbEncrypt([]byte(data), []byte(key))
|
||||
desCfbDecrypt := DesCfbDecrypt(desCfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesCfbEncrypt")
|
||||
assert.Equal(data, string(desCfbDecrypt))
|
||||
}
|
||||
|
||||
func TestDesOfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desOfbEncrypt := DesOfbEncrypt([]byte(data), []byte(key))
|
||||
desOfbDecrypt := DesOfbDecrypt(desOfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesOfbEncrypt")
|
||||
assert.Equal(data, string(desOfbDecrypt))
|
||||
}
|
||||
498
cryptor/encrypt.go
Normal file
498
cryptor/encrypt.go
Normal file
@@ -0,0 +1,498 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package cryptor implements some util functions to encrypt and decrypt.
|
||||
// Note:
|
||||
// 1. for aes crypt function, the `key` param length should be 16, 24 or 32. if not, will panic.
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// AesEcbEncrypt encrypt data with key use AES ECB algorithm
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/jT5irszHx-j
|
||||
func AesEcbEncrypt(data, key []byte) []byte {
|
||||
length := (len(data) + aes.BlockSize) / aes.BlockSize
|
||||
plain := make([]byte, length*aes.BlockSize)
|
||||
|
||||
copy(plain, data)
|
||||
|
||||
pad := byte(len(plain) - len(data))
|
||||
for i := len(data); i < len(plain); i++ {
|
||||
plain[i] = pad
|
||||
}
|
||||
|
||||
encrypted := make([]byte, len(plain))
|
||||
cipher, _ := aes.NewCipher(generateAesKey(key))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||
}
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesEcbDecrypt decrypt data with key use AES ECB algorithm
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/jT5irszHx-j
|
||||
func AesEcbDecrypt(encrypted, key []byte) []byte {
|
||||
cipher, _ := aes.NewCipher(generateAesKey(key))
|
||||
decrypted := make([]byte, len(encrypted))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
|
||||
}
|
||||
|
||||
trim := 0
|
||||
if len(decrypted) > 0 {
|
||||
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
|
||||
}
|
||||
|
||||
return decrypted[:trim]
|
||||
}
|
||||
|
||||
// AesCbcEncrypt encrypt data with key use AES CBC algorithm
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/IOq_g8_lKZD
|
||||
func AesCbcEncrypt(data, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
data = pkcs7Padding(data, block.BlockSize())
|
||||
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(encrypted[aes.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesCbcDecrypt decrypt data with key use AES CBC algorithm
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/IOq_g8_lKZD
|
||||
func AesCbcDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
encrypted = encrypted[aes.BlockSize:]
|
||||
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(encrypted, encrypted)
|
||||
|
||||
decrypted := pkcs7UnPadding(encrypted)
|
||||
return decrypted
|
||||
}
|
||||
|
||||
// AesCtrCrypt encrypt data with key use AES CTR algorithm
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/SpaZO0-5Nsp
|
||||
func AesCtrCrypt(data, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key)
|
||||
|
||||
iv := bytes.Repeat([]byte("1"), block.BlockSize())
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
|
||||
dst := make([]byte, len(data))
|
||||
stream.XORKeyStream(dst, data)
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// AesCfbEncrypt encrypt data with key use AES CFB algorithm
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/tfkF10B13kH
|
||||
func AesCfbEncrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesCfbDecrypt decrypt data with key use AES CFB algorithm
|
||||
// len(encrypted) should be great than 16, len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/tfkF10B13kH
|
||||
func AesCfbDecrypt(encrypted, key []byte) []byte {
|
||||
if len(encrypted) < aes.BlockSize {
|
||||
panic("encrypted data is too short")
|
||||
}
|
||||
|
||||
block, _ := aes.NewCipher(key)
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
encrypted = encrypted[aes.BlockSize:]
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
|
||||
stream.XORKeyStream(encrypted, encrypted)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesOfbEncrypt encrypt data with key use AES OFB algorithm
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/VtHxtkUj-3F
|
||||
func AesOfbEncrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
data = pkcs7Padding(data, aes.BlockSize)
|
||||
encrypted := make([]byte, aes.BlockSize+len(data))
|
||||
iv := encrypted[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(encrypted[aes.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// AesOfbDecrypt decrypt data with key use AES OFB algorithm
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/VtHxtkUj-3F
|
||||
func AesOfbDecrypt(data, key []byte) []byte {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
iv := data[:aes.BlockSize]
|
||||
data = data[aes.BlockSize:]
|
||||
if len(data)%aes.BlockSize != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
decrypted := make([]byte, len(data))
|
||||
mode := cipher.NewOFB(block, iv)
|
||||
mode.XORKeyStream(decrypted, data)
|
||||
|
||||
decrypted = pkcs7UnPadding(decrypted)
|
||||
|
||||
return decrypted
|
||||
}
|
||||
|
||||
// DesEcbEncrypt encrypt data with key use DES ECB algorithm
|
||||
// len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/8qivmPeZy4P
|
||||
func DesEcbEncrypt(data, key []byte) []byte {
|
||||
length := (len(data) + des.BlockSize) / des.BlockSize
|
||||
plain := make([]byte, length*des.BlockSize)
|
||||
copy(plain, data)
|
||||
|
||||
pad := byte(len(plain) - len(data))
|
||||
for i := len(data); i < len(plain); i++ {
|
||||
plain[i] = pad
|
||||
}
|
||||
|
||||
encrypted := make([]byte, len(plain))
|
||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs <= len(data); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
|
||||
}
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesEcbDecrypt decrypt data with key use DES ECB algorithm
|
||||
// len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/8qivmPeZy4P
|
||||
func DesEcbDecrypt(encrypted, key []byte) []byte {
|
||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
||||
decrypted := make([]byte, len(encrypted))
|
||||
|
||||
for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
|
||||
cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
|
||||
}
|
||||
|
||||
trim := 0
|
||||
if len(decrypted) > 0 {
|
||||
trim = len(decrypted) - int(decrypted[len(decrypted)-1])
|
||||
}
|
||||
|
||||
return decrypted[:trim]
|
||||
}
|
||||
|
||||
// DesCbcEncrypt encrypt data with key use DES CBC algorithm
|
||||
// len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/4cC4QvWfe3_1
|
||||
func DesCbcEncrypt(data, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
data = pkcs7Padding(data, block.BlockSize())
|
||||
|
||||
encrypted := make([]byte, des.BlockSize+len(data))
|
||||
iv := encrypted[:des.BlockSize]
|
||||
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
mode.CryptBlocks(encrypted[des.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesCbcDecrypt decrypt data with key use DES CBC algorithm
|
||||
// len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/4cC4QvWfe3_1
|
||||
func DesCbcDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
|
||||
iv := encrypted[:des.BlockSize]
|
||||
encrypted = encrypted[des.BlockSize:]
|
||||
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(encrypted, encrypted)
|
||||
|
||||
decrypted := pkcs7UnPadding(encrypted)
|
||||
return decrypted
|
||||
}
|
||||
|
||||
// DesCtrCrypt encrypt data with key use DES CTR algorithm
|
||||
// len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/9-T6OjKpcdw
|
||||
func DesCtrCrypt(data, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
|
||||
iv := bytes.Repeat([]byte("1"), block.BlockSize())
|
||||
stream := cipher.NewCTR(block, iv)
|
||||
|
||||
dst := make([]byte, len(data))
|
||||
stream.XORKeyStream(dst, data)
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// DesCfbEncrypt encrypt data with key use DES CFB algorithm
|
||||
// len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/y-eNxcFBlxL
|
||||
func DesCfbEncrypt(data, key []byte) []byte {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
encrypted := make([]byte, des.BlockSize+len(data))
|
||||
iv := encrypted[:des.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewCFBEncrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted[des.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesCfbDecrypt decrypt data with key use DES CFB algorithm
|
||||
// len(encrypted) should be great than 16, len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/y-eNxcFBlxL
|
||||
func DesCfbDecrypt(encrypted, key []byte) []byte {
|
||||
block, _ := des.NewCipher(key)
|
||||
if len(encrypted) < des.BlockSize {
|
||||
panic("encrypted data is too short")
|
||||
}
|
||||
iv := encrypted[:des.BlockSize]
|
||||
encrypted = encrypted[des.BlockSize:]
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
stream.XORKeyStream(encrypted, encrypted)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesOfbEncrypt encrypt data with key use DES OFB algorithm
|
||||
// len(key) should be 16, 24 or 32.
|
||||
// Play: https://go.dev/play/p/74KmNadjN1J
|
||||
func DesOfbEncrypt(data, key []byte) []byte {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
data = pkcs7Padding(data, des.BlockSize)
|
||||
encrypted := make([]byte, des.BlockSize+len(data))
|
||||
iv := encrypted[:des.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream := cipher.NewOFB(block, iv)
|
||||
stream.XORKeyStream(encrypted[des.BlockSize:], data)
|
||||
|
||||
return encrypted
|
||||
}
|
||||
|
||||
// DesOfbDecrypt decrypt data with key use DES OFB algorithm
|
||||
// len(key) should be 8.
|
||||
// Play: https://go.dev/play/p/74KmNadjN1J
|
||||
func DesOfbDecrypt(data, key []byte) []byte {
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
iv := data[:des.BlockSize]
|
||||
data = data[des.BlockSize:]
|
||||
if len(data)%des.BlockSize != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
decrypted := make([]byte, len(data))
|
||||
mode := cipher.NewOFB(block, iv)
|
||||
mode.XORKeyStream(decrypted, data)
|
||||
|
||||
decrypted = pkcs7UnPadding(decrypted)
|
||||
|
||||
return decrypted
|
||||
}
|
||||
|
||||
// GenerateRsaKey create rsa private and public pemo file.
|
||||
// Play: https://go.dev/play/p/zutRHrDqs0X
|
||||
func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
|
||||
// private key
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
derText := x509.MarshalPKCS1PrivateKey(privateKey)
|
||||
|
||||
block := pem.Block{
|
||||
Type: "rsa private key",
|
||||
Bytes: derText,
|
||||
}
|
||||
|
||||
file, err := os.Create(priKeyFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = pem.Encode(file, &block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
||||
// public key
|
||||
publicKey := privateKey.PublicKey
|
||||
|
||||
derpText, err := x509.MarshalPKIXPublicKey(&publicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
block = pem.Block{
|
||||
Type: "rsa public key",
|
||||
Bytes: derpText,
|
||||
}
|
||||
|
||||
file, err = os.Create(pubKeyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = pem.Encode(file, &block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RsaEncrypt encrypt data with ras algorithm.
|
||||
// Play: https://go.dev/play/p/rDqTT01SPkZ
|
||||
func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
||||
file, err := os.Open(pubKeyFileName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fileInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
buf := make([]byte, fileInfo.Size())
|
||||
|
||||
_, err = file.Read(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(buf)
|
||||
|
||||
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pubKey := pubInterface.(*rsa.PublicKey)
|
||||
|
||||
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return cipherText
|
||||
}
|
||||
|
||||
// RsaDecrypt decrypt data with ras algorithm.
|
||||
// Play: https://go.dev/play/p/rDqTT01SPkZ
|
||||
func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
||||
file, err := os.Open(privateKeyFileName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fileInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf := make([]byte, fileInfo.Size())
|
||||
defer file.Close()
|
||||
|
||||
_, err = file.Read(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(buf)
|
||||
|
||||
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
plainText, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return plainText
|
||||
}
|
||||
130
cryptor/encrypt_test.go
Normal file
130
cryptor/encrypt_test.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestAesEcbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesEcbEncrypt := AesEcbEncrypt([]byte(data), []byte(key))
|
||||
aesEcbDecrypt := AesEcbDecrypt(aesEcbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesEcbEncrypt")
|
||||
assert.Equal(data, string(aesEcbDecrypt))
|
||||
}
|
||||
|
||||
func TestAesCbcEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesCbcEncrypt := AesCbcEncrypt([]byte(data), []byte(key))
|
||||
aesCbcDecrypt := AesCbcDecrypt(aesCbcEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesCbcEncrypt")
|
||||
assert.Equal(data, string(aesCbcDecrypt))
|
||||
}
|
||||
|
||||
func TestAesCtrCrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesCtrCrypt := AesCtrCrypt([]byte(data), []byte(key))
|
||||
aesCtrDeCrypt := AesCtrCrypt(aesCtrCrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesCtrCrypt")
|
||||
assert.Equal(data, string(aesCtrDeCrypt))
|
||||
}
|
||||
|
||||
func TestAesCfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesCfbEncrypt := AesCfbEncrypt([]byte(data), []byte(key))
|
||||
aesCfbDecrypt := AesCfbDecrypt(aesCfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesCfbEncrypt")
|
||||
assert.Equal(data, string(aesCfbDecrypt))
|
||||
}
|
||||
|
||||
func TestAesOfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
aesOfbEncrypt := AesOfbEncrypt([]byte(data), []byte(key))
|
||||
aesOfbDecrypt := AesOfbDecrypt(aesOfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestAesOfbEncrypt")
|
||||
assert.Equal(data, string(aesOfbDecrypt))
|
||||
}
|
||||
|
||||
func TestDesEcbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desEcbEncrypt := DesEcbEncrypt([]byte(data), []byte(key))
|
||||
desEcbDecrypt := DesEcbDecrypt(desEcbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesEcbEncrypt")
|
||||
assert.Equal(data, string(desEcbDecrypt))
|
||||
}
|
||||
|
||||
func TestDesCbcEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desCbcEncrypt := DesCbcEncrypt([]byte(data), []byte(key))
|
||||
desCbcDecrypt := DesCbcDecrypt(desCbcEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesCbcEncrypt")
|
||||
assert.Equal(data, string(desCbcDecrypt))
|
||||
}
|
||||
|
||||
func TestDesCtrCrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desCtrCrypt := DesCtrCrypt([]byte(data), []byte(key))
|
||||
desCtrDeCrypt := DesCtrCrypt(desCtrCrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesCtrCrypt")
|
||||
assert.Equal(data, string(desCtrDeCrypt))
|
||||
}
|
||||
|
||||
func TestDesCfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desCfbEncrypt := DesCfbEncrypt([]byte(data), []byte(key))
|
||||
desCfbDecrypt := DesCfbDecrypt(desCfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesCfbEncrypt")
|
||||
assert.Equal(data, string(desCfbDecrypt))
|
||||
}
|
||||
|
||||
func TestDesOfbEncrypt(t *testing.T) {
|
||||
data := "hello world"
|
||||
key := "abcdefgh"
|
||||
|
||||
desOfbEncrypt := DesOfbEncrypt([]byte(data), []byte(key))
|
||||
desOfbDecrypt := DesOfbDecrypt(desOfbEncrypt, []byte(key))
|
||||
|
||||
assert := internal.NewAssert(t, "TestDesOfbEncrypt")
|
||||
assert.Equal(data, string(desOfbDecrypt))
|
||||
}
|
||||
|
||||
func TestRsaEncrypt(t *testing.T) {
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
data := []byte("hello world")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
|
||||
assert := internal.NewAssert(t, "TestRsaEncrypt")
|
||||
assert.Equal(string(data), string(decrypted))
|
||||
}
|
||||
134
cryptor/rsa.go
134
cryptor/rsa.go
@@ -1,134 +0,0 @@
|
||||
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package cryptor implements some util functions to encrypt and decrypt.
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"os"
|
||||
)
|
||||
|
||||
// GenerateRsaKey make a rsa private key, and return key file name
|
||||
// Generated key file is `rsa_private.pem` and `rsa_public.pem` in current path
|
||||
func GenerateRsaKey(keySize int, priKeyFile, pubKeyFile string) error {
|
||||
// private key
|
||||
privateKey, err := rsa.GenerateKey(rand.Reader, keySize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
derText := x509.MarshalPKCS1PrivateKey(privateKey)
|
||||
|
||||
block := pem.Block{
|
||||
Type: "rsa private key",
|
||||
Bytes: derText,
|
||||
}
|
||||
|
||||
//file,err := os.Create("rsa_private.pem")
|
||||
file, err := os.Create(priKeyFile)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = pem.Encode(file, &block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
||||
// public key
|
||||
publicKey := privateKey.PublicKey
|
||||
|
||||
derpText, err := x509.MarshalPKIXPublicKey(&publicKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
block = pem.Block{
|
||||
Type: "rsa public key",
|
||||
Bytes: derpText,
|
||||
}
|
||||
|
||||
file, err = os.Create(pubKeyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = pem.Encode(file, &block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RsaEncrypt encrypt data with ras algorithm
|
||||
func RsaEncrypt(data []byte, pubKeyFileName string) []byte {
|
||||
file, err := os.Open(pubKeyFileName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fileInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
buf := make([]byte, fileInfo.Size())
|
||||
|
||||
_, err = file.Read(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(buf)
|
||||
|
||||
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pubKey := pubInterface.(*rsa.PublicKey)
|
||||
|
||||
cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, pubKey, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return cipherText
|
||||
}
|
||||
|
||||
// RsaDecrypt decrypt data with ras algorithm
|
||||
func RsaDecrypt(data []byte, privateKeyFileName string) []byte {
|
||||
file, err := os.Open(privateKeyFileName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fileInfo, err := file.Stat()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf := make([]byte, fileInfo.Size())
|
||||
defer file.Close()
|
||||
|
||||
_, err = file.Read(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
block, _ := pem.Decode(buf)
|
||||
|
||||
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
plainText, err := rsa.DecryptPKCS1v15(rand.Reader, priKey, data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return plainText
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package cryptor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestRsaEncrypt(t *testing.T) {
|
||||
err := GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
data := []byte("hello world")
|
||||
encrypted := RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
|
||||
assert := internal.NewAssert(t, "TestRsaEncrypt")
|
||||
assert.Equal(string(data), string(decrypted))
|
||||
}
|
||||
@@ -8,17 +8,17 @@ import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// List is a linear table, implemented with slice
|
||||
// List is a linear table, implemented with slice.
|
||||
type List[T any] struct {
|
||||
data []T
|
||||
}
|
||||
|
||||
// NewList return a pointer of List
|
||||
// NewList return a pointer of List.
|
||||
func NewList[T any](data []T) *List[T] {
|
||||
return &List[T]{data: data}
|
||||
}
|
||||
|
||||
// Data return list data
|
||||
// Data return list data.
|
||||
func (l *List[T]) Data() []T {
|
||||
return l.data
|
||||
}
|
||||
@@ -31,7 +31,7 @@ func (l *List[T]) ValueOf(index int) (*T, bool) {
|
||||
return &l.data[index], true
|
||||
}
|
||||
|
||||
// IndexOf returns the index of value. if not found return -1
|
||||
// IndexOf returns the index of value. if not found return -1.
|
||||
func (l *List[T]) IndexOf(value T) int {
|
||||
index := -1
|
||||
data := l.data
|
||||
@@ -45,7 +45,7 @@ func (l *List[T]) IndexOf(value T) int {
|
||||
}
|
||||
|
||||
// LastIndexOf returns the index of the last occurrence of the value in this list.
|
||||
// if not found return -1
|
||||
// if not found return -1.
|
||||
func (l *List[T]) LastIndexOf(value T) int {
|
||||
index := -1
|
||||
data := l.data
|
||||
@@ -59,7 +59,7 @@ func (l *List[T]) LastIndexOf(value T) int {
|
||||
}
|
||||
|
||||
// IndexOfFunc returns the first index satisfying f(v)
|
||||
// if not found return -1
|
||||
// if not found return -1.
|
||||
func (l *List[T]) IndexOfFunc(f func(T) bool) int {
|
||||
index := -1
|
||||
data := l.data
|
||||
@@ -73,7 +73,7 @@ func (l *List[T]) IndexOfFunc(f func(T) bool) int {
|
||||
}
|
||||
|
||||
// LastIndexOfFunc returns the index of the last occurrence of the value in this list satisfying f(data[i])
|
||||
// if not found return -1
|
||||
// if not found return -1.
|
||||
func (l *List[T]) LastIndexOfFunc(f func(T) bool) int {
|
||||
index := -1
|
||||
data := l.data
|
||||
@@ -86,7 +86,7 @@ func (l *List[T]) LastIndexOfFunc(f func(T) bool) int {
|
||||
return index
|
||||
}
|
||||
|
||||
// Contain checks if the value in the list or not
|
||||
// Contain checks if the value in the list or not.
|
||||
func (l *List[T]) Contain(value T) bool {
|
||||
data := l.data
|
||||
for _, v := range data {
|
||||
@@ -97,22 +97,22 @@ func (l *List[T]) Contain(value T) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Push append value to the list data
|
||||
// Push append value to the list data.
|
||||
func (l *List[T]) Push(value T) {
|
||||
l.data = append(l.data, value)
|
||||
}
|
||||
|
||||
// InsertAtFirst insert value into list at first index
|
||||
// InsertAtFirst insert value into list at first index.
|
||||
func (l *List[T]) InsertAtFirst(value T) {
|
||||
l.InsertAt(0, value)
|
||||
}
|
||||
|
||||
// InsertAtLast insert value into list at last index
|
||||
// InsertAtLast insert value into list at last index.
|
||||
func (l *List[T]) InsertAtLast(value T) {
|
||||
l.InsertAt(len(l.data), value)
|
||||
}
|
||||
|
||||
// InsertAt insert value into list at index
|
||||
// InsertAt insert value into list at index.
|
||||
func (l *List[T]) InsertAt(index int, value T) {
|
||||
data := l.data
|
||||
size := len(data)
|
||||
@@ -123,7 +123,7 @@ func (l *List[T]) InsertAt(index int, value T) {
|
||||
l.data = append(data[:index], append([]T{value}, data[index:]...)...)
|
||||
}
|
||||
|
||||
// PopFirst delete the first value of list and return it
|
||||
// PopFirst delete the first value of list and return it.
|
||||
func (l *List[T]) PopFirst() (*T, bool) {
|
||||
if len(l.data) == 0 {
|
||||
return nil, false
|
||||
@@ -135,7 +135,7 @@ func (l *List[T]) PopFirst() (*T, bool) {
|
||||
return &v, true
|
||||
}
|
||||
|
||||
// PopLast delete the last value of list and return it
|
||||
// PopLast delete the last value of list and return it.
|
||||
func (l *List[T]) PopLast() (*T, bool) {
|
||||
size := len(l.data)
|
||||
if size == 0 {
|
||||
@@ -148,7 +148,7 @@ func (l *List[T]) PopLast() (*T, bool) {
|
||||
return &v, true
|
||||
}
|
||||
|
||||
// DeleteAt delete the value of list at index
|
||||
// DeleteAt delete the value of list at index.
|
||||
func (l *List[T]) DeleteAt(index int) {
|
||||
data := l.data
|
||||
size := len(data)
|
||||
@@ -199,7 +199,7 @@ func (l *List[T]) UpdateAt(index int, value T) {
|
||||
l.data = append(data[:index], append([]T{value}, data[index+1:]...)...)
|
||||
}
|
||||
|
||||
// Equal compare list to other list, use reflect.DeepEqual
|
||||
// Equal compare list to other list, use reflect.DeepEqual.
|
||||
func (l *List[T]) Equal(other *List[T]) bool {
|
||||
if len(l.data) != len(other.data) {
|
||||
return false
|
||||
@@ -214,17 +214,17 @@ func (l *List[T]) Equal(other *List[T]) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// IsEmpty check if the list is empty or not
|
||||
// IsEmpty check if the list is empty or not.
|
||||
func (l *List[T]) IsEmpty() bool {
|
||||
return len(l.data) == 0
|
||||
}
|
||||
|
||||
// Clear the data of list
|
||||
// Clear the data of list.
|
||||
func (l *List[T]) Clear() {
|
||||
l.data = make([]T, 0)
|
||||
}
|
||||
|
||||
// Clone return a copy of list
|
||||
// Clone return a copy of list.
|
||||
func (l *List[T]) Clone() *List[T] {
|
||||
cl := NewList(make([]T, len(l.data)))
|
||||
copy(cl.data, l.data)
|
||||
@@ -232,7 +232,7 @@ func (l *List[T]) Clone() *List[T] {
|
||||
return cl
|
||||
}
|
||||
|
||||
// Merge two list, return new list, don't change original list
|
||||
// Merge two list, return new list, don't change original list.
|
||||
func (l *List[T]) Merge(other *List[T]) *List[T] {
|
||||
l1, l2 := len(l.data), len(other.data)
|
||||
ml := NewList(make([]T, l1+l2))
|
||||
@@ -243,17 +243,17 @@ func (l *List[T]) Merge(other *List[T]) *List[T] {
|
||||
return ml
|
||||
}
|
||||
|
||||
// Size return number of list data items
|
||||
// Size return number of list data items.
|
||||
func (l *List[T]) Size() int {
|
||||
return len(l.data)
|
||||
}
|
||||
|
||||
// Cap return cap of the inner data
|
||||
// Cap return cap of the inner data.
|
||||
func (l *List[T]) Cap() int {
|
||||
return cap(l.data)
|
||||
}
|
||||
|
||||
// Swap the value of index i and j in list
|
||||
// Swap the value of index i and j in list.
|
||||
func (l *List[T]) Swap(i, j int) {
|
||||
size := len(l.data)
|
||||
if i < 0 || i >= size || j < 0 || j >= size {
|
||||
@@ -262,14 +262,14 @@ func (l *List[T]) Swap(i, j int) {
|
||||
l.data[i], l.data[j] = l.data[j], l.data[i]
|
||||
}
|
||||
|
||||
// Reverse the item order of list
|
||||
// Reverse the item order of list.
|
||||
func (l *List[T]) Reverse() {
|
||||
for i, j := 0, len(l.data)-1; i < j; i, j = i+1, j-1 {
|
||||
l.data[i], l.data[j] = l.data[j], l.data[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Unique remove duplicate items in list
|
||||
// Unique remove duplicate items in list.
|
||||
func (l *List[T]) Unique() {
|
||||
data := l.data
|
||||
size := len(data)
|
||||
@@ -303,7 +303,7 @@ func (l *List[T]) Union(other *List[T]) *List[T] {
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersection creates a new list whose element both be contained in list l and other
|
||||
// Intersection creates a new list whose element both be contained in list l and other.
|
||||
func (l *List[T]) Intersection(other *List[T]) *List[T] {
|
||||
result := NewList(make([]T, 0))
|
||||
|
||||
|
||||
@@ -9,17 +9,20 @@ type theTime struct {
|
||||
unix int64
|
||||
}
|
||||
|
||||
// NewUnixNow return unix timestamp of current time
|
||||
// NewUnixNow return unix timestamp of current time.
|
||||
// Play: https://go.dev/play/p/U4PPx-9D0oz
|
||||
func NewUnixNow() *theTime {
|
||||
return &theTime{unix: time.Now().Unix()}
|
||||
}
|
||||
|
||||
// NewUnix return unix timestamp of specified time
|
||||
// NewUnix return unix timestamp of specified time.
|
||||
// Play: https://go.dev/play/p/psoSuh_kLRt
|
||||
func NewUnix(unix int64) *theTime {
|
||||
return &theTime{unix: unix}
|
||||
}
|
||||
|
||||
// NewFormat return unix timestamp of specified time string, t should be "yyyy-mm-dd hh:mm:ss"
|
||||
// NewFormat return unix timestamp of specified time string, t should be "yyyy-mm-dd hh:mm:ss".
|
||||
// Play: https://go.dev/play/p/VkW08ZOaXPZ
|
||||
func NewFormat(t string) (*theTime, error) {
|
||||
timeLayout := "2006-01-02 15:04:05"
|
||||
loc := time.FixedZone("CST", 8*3600)
|
||||
@@ -30,7 +33,8 @@ func NewFormat(t string) (*theTime, error) {
|
||||
return &theTime{unix: tt.Unix()}, nil
|
||||
}
|
||||
|
||||
// NewISO8601 return unix timestamp of specified iso8601 time string
|
||||
// NewISO8601 return unix timestamp of specified iso8601 time string.
|
||||
// Play: https://go.dev/play/p/mkhOHQkdeA2
|
||||
func NewISO8601(iso8601 string) (*theTime, error) {
|
||||
t, err := time.ParseInLocation(time.RFC3339, iso8601, time.UTC)
|
||||
if err != nil {
|
||||
@@ -39,22 +43,26 @@ func NewISO8601(iso8601 string) (*theTime, error) {
|
||||
return &theTime{unix: t.Unix()}, nil
|
||||
}
|
||||
|
||||
// ToUnix return unix timestamp
|
||||
// ToUnix return unix timestamp.
|
||||
// Play: https://go.dev/play/p/_LUiwAdocjy
|
||||
func (t *theTime) ToUnix() int64 {
|
||||
return t.unix
|
||||
}
|
||||
|
||||
// ToFormat return the time string 'yyyy-mm-dd hh:mm:ss' of unix time
|
||||
// ToFormat return the time string 'yyyy-mm-dd hh:mm:ss' of unix time.
|
||||
// Play: https://go.dev/play/p/VkW08ZOaXPZ
|
||||
func (t *theTime) ToFormat() string {
|
||||
return time.Unix(t.unix, 0).Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
// ToFormatForTpl return the time string which format is specified tpl
|
||||
// ToFormatForTpl return the time string which format is specified tpl.
|
||||
// Play: https://go.dev/play/p/nyXxXcQJ8L5
|
||||
func (t *theTime) ToFormatForTpl(tpl string) string {
|
||||
return time.Unix(t.unix, 0).Format(tpl)
|
||||
}
|
||||
|
||||
// ToFormatForTpl return iso8601 time string
|
||||
// ToFormatForTpl return iso8601 time string.
|
||||
// Play: https://go.dev/play/p/mkhOHQkdeA2
|
||||
func (t *theTime) ToIso8601() string {
|
||||
return time.Unix(t.unix, 0).Format(time.RFC3339)
|
||||
}
|
||||
|
||||
@@ -19,9 +19,6 @@ func TestToUnix(t *testing.T) {
|
||||
func TestToFormat(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestToFormat")
|
||||
|
||||
_, err := NewFormat("2022/03/18 17:04:05")
|
||||
assert.IsNotNil(err)
|
||||
|
||||
tm, err := NewFormat("2022-03-18 17:04:05")
|
||||
assert.IsNil(err)
|
||||
|
||||
|
||||
@@ -54,54 +54,64 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
// AddMinute add or sub minute to the time
|
||||
// AddMinute add or sub minute to the time.
|
||||
// Play: https://go.dev/play/p/nT1heB1KUUK
|
||||
func AddMinute(t time.Time, minute int64) time.Time {
|
||||
return t.Add(time.Minute * time.Duration(minute))
|
||||
}
|
||||
|
||||
// AddHour add or sub hour to the time
|
||||
// AddHour add or sub hour to the time.
|
||||
// Play: https://go.dev/play/p/rcMjd7OCsi5
|
||||
func AddHour(t time.Time, hour int64) time.Time {
|
||||
return t.Add(time.Hour * time.Duration(hour))
|
||||
}
|
||||
|
||||
// AddDay add or sub day to the time
|
||||
// AddDay add or sub day to the time.
|
||||
// Play: https://go.dev/play/p/dIGbs_uTdFa
|
||||
func AddDay(t time.Time, day int64) time.Time {
|
||||
return t.Add(24 * time.Hour * time.Duration(day))
|
||||
}
|
||||
|
||||
// GetNowDate return format yyyy-mm-dd of current date
|
||||
// GetNowDate return format yyyy-mm-dd of current date.
|
||||
// Play: https://go.dev/play/p/PvfkPpcpBBf
|
||||
func GetNowDate() string {
|
||||
return time.Now().Format("2006-01-02")
|
||||
}
|
||||
|
||||
// GetNowTime return format hh-mm-ss of current time
|
||||
// GetNowTime return format hh-mm-ss of current time.
|
||||
// Play: https://go.dev/play/p/l7BNxCkTmJS
|
||||
func GetNowTime() string {
|
||||
return time.Now().Format("15:04:05")
|
||||
}
|
||||
|
||||
// GetNowDateTime return format yyyy-mm-dd hh-mm-ss of current datetime
|
||||
// GetNowDateTime return format yyyy-mm-dd hh-mm-ss of current datetime.
|
||||
// Play: https://go.dev/play/p/pI4AqngD0al
|
||||
func GetNowDateTime() string {
|
||||
return time.Now().Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
// GetZeroHourTimestamp return timestamp of zero hour (timestamp of 00:00)
|
||||
// GetZeroHourTimestamp return timestamp of zero hour (timestamp of 00:00).
|
||||
// Play: https://go.dev/play/p/QmL2oIaGE3q
|
||||
func GetZeroHourTimestamp() int64 {
|
||||
ts := time.Now().Format("2006-01-02")
|
||||
t, _ := time.Parse("2006-01-02", ts)
|
||||
return t.UTC().Unix() - 8*3600
|
||||
}
|
||||
|
||||
// GetNightTimestamp return timestamp of zero hour (timestamp of 23:59)
|
||||
// GetNightTimestamp return timestamp of zero hour (timestamp of 23:59).
|
||||
// Play: https://go.dev/play/p/UolysR3MYP1
|
||||
func GetNightTimestamp() int64 {
|
||||
return GetZeroHourTimestamp() + 86400 - 1
|
||||
}
|
||||
|
||||
// FormatTimeToStr convert time to string
|
||||
// FormatTimeToStr convert time to string.
|
||||
// Play: https://go.dev/play/p/_Ia7M8H_OvE
|
||||
func FormatTimeToStr(t time.Time, format string) string {
|
||||
return t.Format(timeFormat[format])
|
||||
}
|
||||
|
||||
// FormatStrToTime convert string to time
|
||||
// FormatStrToTime convert string to time.
|
||||
// Play: https://go.dev/play/p/1h9FwdU8ql4
|
||||
func FormatStrToTime(str, format string) (time.Time, error) {
|
||||
v, ok := timeFormat[format]
|
||||
if !ok {
|
||||
@@ -111,43 +121,50 @@ func FormatStrToTime(str, format string) (time.Time, error) {
|
||||
return time.Parse(v, str)
|
||||
}
|
||||
|
||||
// BeginOfMinute return beginning minute time of day
|
||||
// BeginOfMinute return beginning minute time of day.
|
||||
// Play: https://go.dev/play/p/ieOLVJ9CiFT
|
||||
func BeginOfMinute(t time.Time) time.Time {
|
||||
y, m, d := t.Date()
|
||||
return time.Date(y, m, d, t.Hour(), t.Minute(), 0, 0, t.Location())
|
||||
}
|
||||
|
||||
// EndOfMinute return end minute time of day
|
||||
// EndOfMinute return end minute time of day.
|
||||
// Play: https://go.dev/play/p/yrL5wGzPj4z
|
||||
func EndOfMinute(t time.Time) time.Time {
|
||||
y, m, d := t.Date()
|
||||
return time.Date(y, m, d, t.Hour(), t.Minute(), 59, int(time.Second-time.Nanosecond), t.Location())
|
||||
}
|
||||
|
||||
// BeginOfHour return beginning hour time of day
|
||||
// BeginOfHour return beginning hour time of day.
|
||||
// Play: https://go.dev/play/p/GhdGFnDWpYs
|
||||
func BeginOfHour(t time.Time) time.Time {
|
||||
y, m, d := t.Date()
|
||||
return time.Date(y, m, d, t.Hour(), 0, 0, 0, t.Location())
|
||||
}
|
||||
|
||||
// EndOfHour return end hour time of day
|
||||
// EndOfHour return end hour time of day.
|
||||
// Play: https://go.dev/play/p/6ce3j_6cVqN
|
||||
func EndOfHour(t time.Time) time.Time {
|
||||
y, m, d := t.Date()
|
||||
return time.Date(y, m, d, t.Hour(), 59, 59, int(time.Second-time.Nanosecond), t.Location())
|
||||
}
|
||||
|
||||
// BeginOfDay return beginning hour time of day
|
||||
// BeginOfDay return beginning hour time of day.
|
||||
// Play: https://go.dev/play/p/94m_UT6cWs9
|
||||
func BeginOfDay(t time.Time) time.Time {
|
||||
y, m, d := t.Date()
|
||||
return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
|
||||
}
|
||||
|
||||
// EndOfDay return end time of day
|
||||
// EndOfDay return end time of day.
|
||||
// Play: https://go.dev/play/p/eMBOvmq5Ih1
|
||||
func EndOfDay(t time.Time) time.Time {
|
||||
y, m, d := t.Date()
|
||||
return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
|
||||
}
|
||||
|
||||
// BeginOfWeek return beginning week, default week begin from Sunday
|
||||
// BeginOfWeek return beginning week, default week begin from Sunday.
|
||||
// Play: https://go.dev/play/p/ynjoJPz7VNV
|
||||
func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time {
|
||||
var beginFromWeekday = time.Sunday
|
||||
if len(beginFrom) > 0 {
|
||||
@@ -161,7 +178,8 @@ func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time {
|
||||
return beginOfWeek
|
||||
}
|
||||
|
||||
// EndOfWeek return end week time, default week end with Saturday
|
||||
// EndOfWeek return end week time, default week end with Saturday.
|
||||
// Play: https://go.dev/play/p/i08qKXD9flf
|
||||
func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time {
|
||||
var endWithWeekday = time.Saturday
|
||||
if len(endWith) > 0 {
|
||||
@@ -175,24 +193,28 @@ func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time {
|
||||
return endWithWeek
|
||||
}
|
||||
|
||||
// BeginOfMonth return beginning of month
|
||||
// BeginOfMonth return beginning of month.
|
||||
// Play: https://go.dev/play/p/bWXVFsmmzwL
|
||||
func BeginOfMonth(t time.Time) time.Time {
|
||||
y, m, _ := t.Date()
|
||||
return time.Date(y, m, 1, 0, 0, 0, 0, t.Location())
|
||||
}
|
||||
|
||||
// EndOfMonth return end of month
|
||||
// EndOfMonth return end of month.
|
||||
// Play: https://go.dev/play/p/_GWh10B3Nqi
|
||||
func EndOfMonth(t time.Time) time.Time {
|
||||
return BeginOfMonth(t).AddDate(0, 1, 0).Add(-time.Nanosecond)
|
||||
}
|
||||
|
||||
// BeginOfYear return beginning of year
|
||||
// BeginOfYear return the date time at the begin of year.
|
||||
// Play: https://go.dev/play/p/i326DSwLnV8
|
||||
func BeginOfYear(t time.Time) time.Time {
|
||||
y, _, _ := t.Date()
|
||||
return time.Date(y, time.January, 1, 0, 0, 0, 0, t.Location())
|
||||
}
|
||||
|
||||
// EndOfYear return end of year
|
||||
// EndOfYear return the date time at the end of year.
|
||||
// Play: https://go.dev/play/p/G01cKlMCvNm
|
||||
func EndOfYear(t time.Time) time.Time {
|
||||
return BeginOfYear(t).AddDate(1, 0, 0).Add(-time.Nanosecond)
|
||||
}
|
||||
|
||||
323
datetime/datetime_example_test.go
Normal file
323
datetime/datetime_example_test.go
Normal file
@@ -0,0 +1,323 @@
|
||||
package datetime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleAddDay() {
|
||||
now := time.Now()
|
||||
|
||||
tomorrow := AddDay(now, 1)
|
||||
diff1 := tomorrow.Sub(now)
|
||||
|
||||
yesterday := AddDay(now, -1)
|
||||
diff2 := yesterday.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
|
||||
// Output:
|
||||
// 24h0m0s
|
||||
// -24h0m0s
|
||||
}
|
||||
|
||||
func ExampleAddHour() {
|
||||
now := time.Now()
|
||||
|
||||
after2Hours := AddHour(now, 2)
|
||||
diff1 := after2Hours.Sub(now)
|
||||
|
||||
before2Hours := AddHour(now, -2)
|
||||
diff2 := before2Hours.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
|
||||
// Output:
|
||||
// 2h0m0s
|
||||
// -2h0m0s
|
||||
}
|
||||
|
||||
func ExampleAddMinute() {
|
||||
now := time.Now()
|
||||
|
||||
after2Minutes := AddMinute(now, 2)
|
||||
diff1 := after2Minutes.Sub(now)
|
||||
|
||||
before2Minutes := AddMinute(now, -2)
|
||||
diff2 := before2Minutes.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
|
||||
// Output:
|
||||
// 2m0s
|
||||
// -2m0s
|
||||
}
|
||||
|
||||
func ExampleGetNowDate() {
|
||||
result := GetNowDate()
|
||||
|
||||
expected := time.Now().Format("2006-01-02")
|
||||
|
||||
fmt.Println(result == expected)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleGetNowTime() {
|
||||
result := GetNowTime()
|
||||
|
||||
expected := time.Now().Format("15:04:05")
|
||||
|
||||
fmt.Println(result == expected)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleGetNowDateTime() {
|
||||
result := GetNowDateTime()
|
||||
|
||||
expected := time.Now().Format("2006-01-02 15:04:05")
|
||||
|
||||
fmt.Println(result == expected)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
// func ExampleGetZeroHourTimestamp() {
|
||||
// ts := GetZeroHourTimestamp()
|
||||
|
||||
// fmt.Println(ts)
|
||||
|
||||
// // Output:
|
||||
// // 1673107200
|
||||
// }
|
||||
|
||||
// func ExampleGetNightTimestamp() {
|
||||
// ts := GetNightTimestamp()
|
||||
|
||||
// fmt.Println(ts)
|
||||
|
||||
// // Output:
|
||||
// // 1673193599
|
||||
// }
|
||||
|
||||
func ExampleFormatTimeToStr() {
|
||||
datetime, _ := time.Parse("2006-01-02 15:04:05", "2021-01-02 16:04:08")
|
||||
|
||||
result1 := FormatTimeToStr(datetime, "yyyy-mm-dd hh:mm:ss")
|
||||
result2 := FormatTimeToStr(datetime, "yyyy-mm-dd")
|
||||
result3 := FormatTimeToStr(datetime, "dd-mm-yy hh:mm:ss")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 2021-01-02 16:04:08
|
||||
// 2021-01-02
|
||||
// 02-01-21 16:04:08
|
||||
}
|
||||
|
||||
func ExampleFormatStrToTime() {
|
||||
result1, _ := FormatStrToTime("2021-01-02 16:04:08", "yyyy-mm-dd hh:mm:ss")
|
||||
result2, _ := FormatStrToTime("2021-01-02", "yyyy-mm-dd")
|
||||
result3, _ := FormatStrToTime("02-01-21 16:04:08", "dd-mm-yy hh:mm:ss")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 2021-01-02 16:04:08 +0000 UTC
|
||||
// 2021-01-02 00:00:00 +0000 UTC
|
||||
// 2021-01-02 16:04:08 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleBeginOfMinute() {
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
|
||||
result := BeginOfMinute(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-08 18:50:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleEndOfMinute() {
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
|
||||
result := EndOfMinute(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-08 18:50:59.999999999 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleBeginOfHour() {
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
|
||||
result := BeginOfHour(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-08 18:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleEndOfHour() {
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
|
||||
result := EndOfHour(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-08 18:59:59.999999999 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleBeginOfDay() {
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
|
||||
result := BeginOfDay(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-08 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleEndOfDay() {
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
|
||||
result := EndOfDay(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-08 23:59:59.999999999 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleBeginOfWeek() {
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
|
||||
result := BeginOfWeek(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-08 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleEndOfWeek() {
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
|
||||
result := EndOfWeek(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-14 23:59:59.999999999 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleBeginOfMonth() {
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
|
||||
result := BeginOfMonth(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-01 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleEndOfMonth() {
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
|
||||
result := EndOfMonth(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-31 23:59:59.999999999 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleBeginOfYear() {
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
|
||||
result := BeginOfYear(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-01 00:00:00 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleEndOfYear() {
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
|
||||
result := EndOfYear(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-12-31 23:59:59.999999999 +0000 UTC
|
||||
}
|
||||
|
||||
func ExampleNewUnix() {
|
||||
result := NewUnix(1647597438)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// &{1647597438}
|
||||
}
|
||||
|
||||
func ExampleNewUnixNow() {
|
||||
tm1 := NewUnixNow()
|
||||
|
||||
unixTimestamp := tm1.ToUnix()
|
||||
|
||||
tm2 := NewUnix(unixTimestamp)
|
||||
|
||||
fmt.Println(reflect.DeepEqual(tm1, tm2))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
// func ExampleNewFormat() {
|
||||
// tm, err := NewFormat("2022-03-18 17:04:05")
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
// result := tm.ToFormat()
|
||||
|
||||
// fmt.Println(result)
|
||||
|
||||
// // Output:
|
||||
// // 2022-03-18 17:04:05
|
||||
// }
|
||||
|
||||
// func ExampleNewISO8601() {
|
||||
// tm, err := NewISO8601("2006-01-02T15:04:05.999Z")
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
// result := tm.ToIso8601()
|
||||
|
||||
// fmt.Println(result)
|
||||
|
||||
// // Output:
|
||||
// // 2006-01-02T23:04:05+08:00
|
||||
// }
|
||||
@@ -52,8 +52,8 @@ func TestGetNowDate(t *testing.T) {
|
||||
assert.Equal(expected, GetNowDate())
|
||||
}
|
||||
|
||||
func TestGetNotTime(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGetNotTime")
|
||||
func TestGetNowTime(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestGetNowTime")
|
||||
expected := time.Now().Format("15:04:05")
|
||||
assert.Equal(expected, GetNowTime())
|
||||
}
|
||||
@@ -81,7 +81,6 @@ func TestFormatTimeToStr(t *testing.T) {
|
||||
for i := 0; i < len(cases); i++ {
|
||||
actual := FormatTimeToStr(datetime, cases[i])
|
||||
assert.Equal(expected[i], actual)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
# Algorithm
|
||||
|
||||
Package algorithm implements some basic algorithm. eg. sort, search.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/sort.go](https://github.com/duke-git/lancet/blob/main/algorithm/sort.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/sort.go](https://github.com/duke-git/lancet/blob/main/algorithm/sort.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
@@ -22,27 +24,25 @@ import (
|
||||
|
||||
## Index
|
||||
|
||||
- [BubbleSort](#BubbleSort)
|
||||
- [InsertionSort](#InsertionSort)
|
||||
- [SelectionSort](#SelectionSort)
|
||||
- [ShellSort](#ShellSort)
|
||||
- [QuickSort](#QuickSort)
|
||||
- [HeapSort](#HeapSort)
|
||||
- [MergeSort](#MergeSort)
|
||||
- [CountSort](#CountSort)
|
||||
- [BinarySearch](#BinarySearch)
|
||||
- [BinaryIterativeSearch](#BinaryIterativeSearch)
|
||||
- [LinearSearch](#LinearSearch)
|
||||
- [LRUCache](#LRUCache)
|
||||
|
||||
- [BubbleSort](#BubbleSort)
|
||||
- [InsertionSort](#InsertionSort)
|
||||
- [SelectionSort](#SelectionSort)
|
||||
- [ShellSort](#ShellSort)
|
||||
- [QuickSort](#QuickSort)
|
||||
- [HeapSort](#HeapSort)
|
||||
- [MergeSort](#MergeSort)
|
||||
- [CountSort](#CountSort)
|
||||
- [BinarySearch](#BinarySearch)
|
||||
- [BinaryIterativeSearch](#BinaryIterativeSearch)
|
||||
- [LinearSearch](#LinearSearch)
|
||||
- [LRUCache](#LRUCache)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
|
||||
### <span id="BubbleSort">BubbleSort</span>
|
||||
|
||||
<p>Sort slice with bubble sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -50,6 +50,7 @@ import (
|
||||
```go
|
||||
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -60,34 +61,36 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
func main() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.BubbleSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
algorithm.BubbleSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="InsertionSort">InsertionSort</span>
|
||||
|
||||
<p>Sort slice with insertion sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -95,6 +98,7 @@ func main() {
|
||||
```go
|
||||
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -105,54 +109,51 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
type people struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
// PeopleAageComparator sort people slice by age field
|
||||
type peopleAgeComparator struct{}
|
||||
|
||||
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
|
||||
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
|
||||
p1, _ := v1.(people)
|
||||
p2, _ := v2.(people)
|
||||
|
||||
//ascending order
|
||||
if p1.Age < p2.Age {
|
||||
return -1
|
||||
} else if p1.Age > p2.Age {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
type people struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
// PeopleAageComparator sort people slice by age field
|
||||
type peopleAgeComparator struct{}
|
||||
|
||||
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
|
||||
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
|
||||
p1, _ := v1.(people)
|
||||
p2, _ := v2.(people)
|
||||
|
||||
//ascending order
|
||||
if p1.Age < p2.Age {
|
||||
return -1
|
||||
} else if p1.Age > p2.Age {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
|
||||
//decending order
|
||||
// if p1.Age > p2.Age {
|
||||
// return -1
|
||||
// } else if p1.Age < p2.Age {
|
||||
// return 1
|
||||
// }
|
||||
}
|
||||
|
||||
var peoples = []people{
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
{Name: "b", Age: 10},
|
||||
{Name: "c", Age: 17},
|
||||
{Name: "d", Age: 8},
|
||||
{Name: "e", Age: 28},
|
||||
}
|
||||
|
||||
comparator := &peopleAgeComparator{}
|
||||
|
||||
algorithm.InsertionSort(peoples, comparator)
|
||||
|
||||
fmt.Println(peoples) //[{d 8} {b 10} {c 17} {a 20} {e 28}]
|
||||
fmt.Println(peoples)
|
||||
|
||||
// Output:
|
||||
// [{d 8} {b 10} {c 17} {a 20} {e 28}]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="SelectionSort">SelectionSort</span>
|
||||
|
||||
<p>Sort slice with selection sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -160,6 +161,7 @@ func main() {
|
||||
```go
|
||||
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -170,34 +172,36 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
func main() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.SelectionSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
algorithm.SelectionSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ShellSort">ShellSort</span>
|
||||
|
||||
<p>Sort slice with shell sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -205,6 +209,7 @@ func main() {
|
||||
```go
|
||||
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -215,34 +220,36 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
func main() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.ShellSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
algorithm.ShellSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="QuickSort">QuickSort</span>
|
||||
|
||||
<p>Sort slice with quick sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -250,6 +257,7 @@ func main() {
|
||||
```go
|
||||
func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -260,34 +268,36 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
func main() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.QuickSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
algorithm.QuickSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="HeapSort">HeapSort</span>
|
||||
|
||||
<p>Sort slice with heap sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -295,6 +305,7 @@ func main() {
|
||||
```go
|
||||
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -305,34 +316,36 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
func main() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.HeapSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
algorithm.HeapSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="MergeSort">MergeSort</span>
|
||||
|
||||
<p>Sort slice with merge sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -340,6 +353,7 @@ func main() {
|
||||
```go
|
||||
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -350,33 +364,36 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
func main() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.MergeSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
algorithm.MergeSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="CountSort">CountSort</span>
|
||||
|
||||
<p>Sort slice with count sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -384,6 +401,7 @@ func main() {
|
||||
```go
|
||||
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -394,34 +412,37 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
type intComparator struct{}
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
func main() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
sortedSlice := algorithm.CountSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(sortedSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
sortedNums := algorithm.CountSort(numbers, comparator)
|
||||
|
||||
fmt.Println(sortedNums)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BinarySearch">BinarySearch</span>
|
||||
|
||||
<p>BinarySearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -429,6 +450,7 @@ func main() {
|
||||
```go
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -439,35 +461,39 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
func main() {
|
||||
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
foundIndex := algorithm.BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(foundIndex) //4
|
||||
|
||||
notFoundIndex := algorithm.BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(notFoundIndex) //-1
|
||||
result1 := algorithm.BinarySearch(numbers, 5, 0, len(numbers)-1, comparator)
|
||||
result2 := algorithm.BinarySearch(numbers, 9, 0, len(numbers)-1, comparator)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// -1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
|
||||
|
||||
<p>BinaryIterativeSearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -475,6 +501,7 @@ func main() {
|
||||
```go
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -485,43 +512,47 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
func main() {
|
||||
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
foundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(foundIndex) //4
|
||||
|
||||
notFoundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(notFoundIndex) //-1
|
||||
result1 := algorithm.BinaryIterativeSearch(numbers, 5, 0, len(numbers)-1, comparator)
|
||||
result2 := algorithm.BinaryIterativeSearch(numbers, 9, 0, len(numbers)-1, comparator)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// -1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinearSearch">LinearSearch</span>
|
||||
<p>LinearSearch Simple linear search algorithm that iterates over all elements of an slice. If a target is found, the index of the target is returned. Else the function return -1.</p>
|
||||
|
||||
<p>return the index of target in slice base on equal function.If a target is found, the index of the target is returned. Else the function return -1.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int
|
||||
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -533,35 +564,26 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
numbers := []int{3, 4, 5, 3, 2, 1}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
equalFunc := func(a, b int) bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
foundIndex := algorithm.LinearSearch(intSlice, 5, comparator)
|
||||
fmt.Println(foundIndex) //2
|
||||
result1 := algorithm.LinearSearch(numbers, 3, equalFunc)
|
||||
result2 := algorithm.LinearSearch(numbers, 6, equalFunc)
|
||||
|
||||
notFoundIndex := algorithm.LinearSearch(sortedNumbers, 0, comparator)
|
||||
fmt.Println(notFoundIndex) //-1
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// -1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LRUCache">LRUCache</span>
|
||||
|
||||
<p>LRUCache implements mem cache with lru.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -570,7 +592,10 @@ func main() {
|
||||
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
|
||||
func (l *LRUCache[K, V]) Get(key K) (V, bool)
|
||||
func (l *LRUCache[K, V]) Put(key K, value V)
|
||||
func (l *LRUCache[K, V]) Delete(key K) bool
|
||||
func (l *LRUCache[K, V]) Len() int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -587,9 +612,25 @@ func main() {
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
_, ok := cache.Get(0) // ok -> false
|
||||
result1, ok1 := cache.Get(1)
|
||||
result2, ok2 := cache.Get(2)
|
||||
result3, ok3 := cache.Get(3)
|
||||
|
||||
v, ok := cache.Get(1) // v->1, ok->true
|
||||
fmt.Println(result1, ok1)
|
||||
fmt.Println(result2, ok2)
|
||||
fmt.Println(result3, ok3)
|
||||
|
||||
fmt.Println(cache.Len())
|
||||
|
||||
ok := cache.Delete(2)
|
||||
fmt.Println(ok)
|
||||
|
||||
|
||||
// Output:
|
||||
// 1 true
|
||||
// 2 true
|
||||
// 0 false
|
||||
// 2
|
||||
// true
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
# Algorithm
|
||||
algorithm算法包实现一些基本算法,sort,search,lrucache。
|
||||
|
||||
algorithm 算法包实现一些基本算法,sort,search,lrucache。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/sort.go](https://github.com/duke-git/lancet/blob/main/algorithm/sort.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/sort.go](https://github.com/duke-git/lancet/blob/main/algorithm/sort.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/search.go](https://github.com/duke-git/lancet/blob/main/algorithm/search.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go](https://github.com/duke-git/lancet/blob/main/algorithm/lru_cache.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
@@ -22,35 +24,34 @@ import (
|
||||
|
||||
## 目录
|
||||
|
||||
- [BubbleSort](#BubbleSort)
|
||||
- [InsertionSort](#InsertionSort)
|
||||
- [SelectionSort](#SelectionSort)
|
||||
- [ShellSort](#ShellSort)
|
||||
- [QuickSort](#QuickSort)
|
||||
- [HeapSort](#HeapSort)
|
||||
- [MergeSort](#MergeSort)
|
||||
- [CountSort](#CountSort)
|
||||
- [BinarySearch](#BinarySearch)
|
||||
- [BinaryIterativeSearch](#BinaryIterativeSearch)
|
||||
- [LinearSearch](#LinearSearch)
|
||||
- [LRUCache](#LRUCache)
|
||||
|
||||
- [BubbleSort](#BubbleSort)
|
||||
- [InsertionSort](#InsertionSort)
|
||||
- [SelectionSort](#SelectionSort)
|
||||
- [ShellSort](#ShellSort)
|
||||
- [QuickSort](#QuickSort)
|
||||
- [HeapSort](#HeapSort)
|
||||
- [MergeSort](#MergeSort)
|
||||
- [CountSort](#CountSort)
|
||||
- [BinarySearch](#BinarySearch)
|
||||
- [BinaryIterativeSearch](#BinaryIterativeSearch)
|
||||
- [LinearSearch](#LinearSearch)
|
||||
- [LRUCache](#LRUCache)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
|
||||
|
||||
### <span id="BubbleSort">BubbleSort</span>
|
||||
<p>冒泡排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<p>冒泡排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -60,42 +61,45 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
func main() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.BubbleSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
algorithm.BubbleSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="InsertionSort">InsertionSort</span>
|
||||
<p>插入排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<p>插入排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -105,62 +109,60 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
type people struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
// PeopleAageComparator sort people slice by age field
|
||||
type peopleAgeComparator struct{}
|
||||
|
||||
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
|
||||
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
|
||||
p1, _ := v1.(people)
|
||||
p2, _ := v2.(people)
|
||||
|
||||
//ascending order
|
||||
if p1.Age < p2.Age {
|
||||
return -1
|
||||
} else if p1.Age > p2.Age {
|
||||
return 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {
|
||||
type people struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
// PeopleAageComparator sort people slice by age field
|
||||
type peopleAgeComparator struct{}
|
||||
|
||||
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
|
||||
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
|
||||
p1, _ := v1.(people)
|
||||
p2, _ := v2.(people)
|
||||
|
||||
//ascending order
|
||||
if p1.Age < p2.Age {
|
||||
return -1
|
||||
} else if p1.Age > p2.Age {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
|
||||
//decending order
|
||||
// if p1.Age > p2.Age {
|
||||
// return -1
|
||||
// } else if p1.Age < p2.Age {
|
||||
// return 1
|
||||
// }
|
||||
}
|
||||
|
||||
var peoples = []people{
|
||||
peoples := []people{
|
||||
{Name: "a", Age: 20},
|
||||
{Name: "b", Age: 10},
|
||||
{Name: "c", Age: 17},
|
||||
{Name: "d", Age: 8},
|
||||
{Name: "e", Age: 28},
|
||||
}
|
||||
|
||||
comparator := &peopleAgeComparator{}
|
||||
|
||||
algorithm.InsertionSort(peoples, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[{d 8} {b 10} {c 17} {a 20} {e 28}]
|
||||
fmt.Println(peoples)
|
||||
|
||||
// Output:
|
||||
// [{d 8} {b 10} {c 17} {a 20} {e 28}]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="SelectionSort">SelectionSort</span>
|
||||
<p>选择排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<p>选择排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -170,42 +172,45 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
func main() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.SelectionSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
algorithm.SelectionSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="ShellSort">ShellSort</span>
|
||||
<p>希尔排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<p>希尔排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -215,42 +220,45 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
func main() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.ShellSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
algorithm.ShellSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="QuickSort">QuickSort</span>
|
||||
<p>快速排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<p>快速排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
|
||||
func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -260,42 +268,45 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
func main() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.QuickSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
algorithm.QuickSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="HeapSort">HeapSort</span>
|
||||
<p>堆排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<p>堆排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
|
||||
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -305,42 +316,45 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
func main() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.HeapSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
algorithm.HeapSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="MergeSort">MergeSort</span>
|
||||
<p>归并排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<p>归并排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -350,41 +364,45 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
func main() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
algorithm.MergeSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
algorithm.MergeSort(numbers, comparator)
|
||||
|
||||
fmt.Println(numbers)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="CountSort">CountSort</span>
|
||||
<p>计数排序,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<p>计数排序,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -394,42 +412,46 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
type intComparator struct{}
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
func main() {
|
||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
sortedSlice := algorithm.CountSort(intSlice, comparator)
|
||||
|
||||
fmt.Println(sortedSlice) //[]int{1, 2, 3, 4, 5, 6}
|
||||
sortedNums := algorithm.CountSort(numbers, comparator)
|
||||
|
||||
fmt.Println(sortedNums)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5 6]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BinarySearch">BinarySearch</span>
|
||||
<p>二分递归查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<p>二分递归查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -439,43 +461,48 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
func main() {
|
||||
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
foundIndex := algorithm.BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(foundIndex) //4
|
||||
|
||||
notFoundIndex := algorithm.BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(notFoundIndex) //-1
|
||||
result1 := algorithm.BinarySearch(numbers, 5, 0, len(numbers)-1, comparator)
|
||||
result2 := algorithm.BinarySearch(numbers, 9, 0, len(numbers)-1, comparator)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// -1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
|
||||
<p>二分迭代查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<p>二分迭代查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -485,44 +512,48 @@ import (
|
||||
"github.com/duke-git/lancet/v2/algorithm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
type intComparator struct{}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
func main() {
|
||||
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||
comparator := &intComparator{}
|
||||
foundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(foundIndex) //4
|
||||
|
||||
notFoundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator)
|
||||
fmt.Println(notFoundIndex) //-1
|
||||
result1 := algorithm.BinaryIterativeSearch(numbers, 5, 0, len(numbers)-1, comparator)
|
||||
result2 := algorithm.BinaryIterativeSearch(numbers, 9, 0, len(numbers)-1, comparator)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// -1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LinearSearch">LinearSearch</span>
|
||||
<p>线性查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator</p>
|
||||
|
||||
<p>基于传入的相等函数线性查找元素,返回元素索引,未找到元素返回-1。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int
|
||||
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -533,36 +564,27 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
type intComparator struct{}
|
||||
numbers := []int{3, 4, 5, 3, 2, 1}
|
||||
|
||||
func (c *intComparator) Compare(v1 any, v2 any) int {
|
||||
val1, _ := v1.(int)
|
||||
val2, _ := v2.(int)
|
||||
|
||||
//ascending order
|
||||
if val1 < val2 {
|
||||
return -1
|
||||
} else if val1 > val2 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
equalFunc := func(a, b int) bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
intSlice := []int{2, 1, 5, 3, 6, 4}
|
||||
comparator := &intComparator{}
|
||||
foundIndex := algorithm.LinearSearch(intSlice, 5, comparator)
|
||||
fmt.Println(foundIndex) //2
|
||||
result1 := algorithm.LinearSearch(numbers, 3, equalFunc)
|
||||
result2 := algorithm.LinearSearch(numbers, 6, equalFunc)
|
||||
|
||||
notFoundIndex := algorithm.LinearSearch(sortedNumbers, 0, comparator)
|
||||
fmt.Println(notFoundIndex) //-1
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// -1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LRUCache">LRUCache</span>
|
||||
<p>lru实现缓存</p>
|
||||
|
||||
<p>lru算法实现缓存。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -570,8 +592,11 @@ func main() {
|
||||
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
|
||||
func (l *LRUCache[K, V]) Get(key K) (V, bool)
|
||||
func (l *LRUCache[K, V]) Put(key K, value V)
|
||||
func (l *LRUCache[K, V]) Delete(key K) bool
|
||||
func (l *LRUCache[K, V]) Len() int
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -587,9 +612,25 @@ func main() {
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
|
||||
_, ok := cache.Get(0) // ok -> false
|
||||
result1, ok1 := cache.Get(1)
|
||||
result2, ok2 := cache.Get(2)
|
||||
result3, ok3 := cache.Get(3)
|
||||
|
||||
v, ok := cache.Get(1) // v->1, ok->true
|
||||
fmt.Println(result1, ok1)
|
||||
fmt.Println(result2, ok2)
|
||||
fmt.Println(result3, ok3)
|
||||
|
||||
fmt.Println(cache.Len())
|
||||
|
||||
ok := cache.Delete(2)
|
||||
fmt.Println(ok)
|
||||
|
||||
|
||||
// Output:
|
||||
// 1 true
|
||||
// 2 true
|
||||
// 0 false
|
||||
// 2
|
||||
// true
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
@@ -38,13 +38,13 @@ import (
|
||||
|
||||
## Channel
|
||||
### <span id="NewChannel">NewChannel</span>
|
||||
<p>return a Channel pointer instance.</p>
|
||||
<p>Create a Channel pointer instance.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type Channel struct {}
|
||||
func NewChannel() *Channel
|
||||
type Channel[T any] struct
|
||||
func NewChannel[T any]() *Channel[T]
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -57,12 +57,10 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Bridge">Bridge</span>
|
||||
|
||||
<p>Link multiple channels into one channel until cancel the context.</p>
|
||||
@@ -70,7 +68,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
|
||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -84,42 +82,45 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
genVals := func() <-chan <-chan any {
|
||||
chanStream := make(chan (<-chan any))
|
||||
go func() {
|
||||
defer close(chanStream)
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan any, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
}
|
||||
}()
|
||||
return chanStream
|
||||
}
|
||||
c := concurrency.NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
out := make(chan (<-chan int))
|
||||
go func() {
|
||||
defer close(out)
|
||||
for i := 1; i <= 5; i++ {
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
out <- stream
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
index := 0
|
||||
for val := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
|
||||
}
|
||||
for v := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
// 4
|
||||
// 5
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="FanIn">FanIn</span>
|
||||
|
||||
<p>merge multiple channels into one channel until cancel the context.</p>
|
||||
<p>Merge multiple channels into one channel until cancel the context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
|
||||
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -133,33 +134,32 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
channels := make([]<-chan any, 3)
|
||||
c := concurrency.NewChannel[int]()
|
||||
channels := make([]<-chan int, 2)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
||||
}
|
||||
for i := 0; i < 2; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
|
||||
}
|
||||
|
||||
mergedChannel := c.FanIn(ctx, channels...)
|
||||
chs := c.FanIn(ctx, channels...)
|
||||
|
||||
for val := range mergedChannel {
|
||||
fmt.Println("\t%d\n", val) //1,2,1,0,0,1,0,2,2 (order not for sure)
|
||||
}
|
||||
for v := range chs {
|
||||
fmt.Println(v) //1 1 0 0 or 0 0 1 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Repeat">Repeat</span>
|
||||
|
||||
<p>Return a chan, put param `values` into the chan repeatly until cancel the context.</p>
|
||||
<p>Create channel, put values into the channel repeatly until cancel the context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
|
||||
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -173,29 +173,70 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v) //1, 2, 1, 2, 1
|
||||
}
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Generate">Generate</span>
|
||||
|
||||
<p>Creates a channel, then put values into the channel.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Generate(ctx, 1, 2, 3)
|
||||
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RepeatFn">RepeatFn</span>
|
||||
|
||||
<p>Return a chan, excutes fn repeatly, and put the result into retruned chan until cancel context.</p>
|
||||
<p>Create a channel, excutes fn repeatly, and put the result into the channel, until close context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
|
||||
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -209,24 +250,27 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() any {
|
||||
s := "a"
|
||||
return s
|
||||
}
|
||||
c := concurrency.NewChannel()
|
||||
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
fn := func() string {
|
||||
return "hello"
|
||||
}
|
||||
|
||||
for v := range dataStream {
|
||||
fmt.Println(v) //a, a, a
|
||||
}
|
||||
c := concurrency.NewChannel[string]()
|
||||
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
// hello
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Or">Or</span>
|
||||
|
||||
<p>Read one or more channels into one channel, will close when any readin channel is closed.</p>
|
||||
@@ -234,7 +278,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Or(channels ...<-chan any) <-chan any
|
||||
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -248,33 +292,28 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan interface{})
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
}()
|
||||
return c
|
||||
}
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan any)
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
}()
|
||||
return c
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
start := time.Now()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
sig(3*time.Second),
|
||||
sig(4*time.Second),
|
||||
sig(5*time.Second),
|
||||
)
|
||||
c := concurrency.NewChannel[any]()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
sig(3*time.Second),
|
||||
)
|
||||
|
||||
fmt.Println("done after %v", time.Since(start)) //1.003s
|
||||
fmt.Println("done after %v", time.Since(start)) //1.003s
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="OrDone">OrDone</span>
|
||||
|
||||
<p>Read a channel into another channel, will close until cancel context.</p>
|
||||
@@ -282,7 +321,7 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
|
||||
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -296,29 +335,31 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
|
||||
for val := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(val) //1
|
||||
}
|
||||
for v := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Take">Take</span>
|
||||
|
||||
<p>Return a chan whose values are tahken from another chan until cancel context.</p>
|
||||
<p>Create a channel whose values are taken from another channel with limit number.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
|
||||
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -332,36 +373,39 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan any, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
numbers <- 4
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
numbers := make(chan int, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
numbers <- 4
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
for val := range intStream {
|
||||
fmt.Println(val) //1, 2, 3
|
||||
}
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Tee">Tee</span>
|
||||
|
||||
<p>Split one chanel into two channels until cancel context.</p>
|
||||
<p>Split one chanel into two channels, until cancel the context.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
|
||||
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -375,16 +419,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
|
||||
|
||||
out1, out2 := c.Tee(ctx, inStream)
|
||||
for val := range out1 {
|
||||
fmt.Println(val) //1
|
||||
fmt.Println(<-out2) //1
|
||||
}
|
||||
ch1, ch2 := c.Tee(ctx, intStream)
|
||||
|
||||
for v := range ch1 {
|
||||
fmt.Println(v)
|
||||
fmt.Println(<-ch2)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
@@ -38,13 +38,13 @@ import (
|
||||
|
||||
### Channel
|
||||
### <span id="NewChannel">NewChannel</span>
|
||||
<p>返回一个 Channel 指针实例</p>
|
||||
<p>返回一个Channel指针实例</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type Channel struct {}
|
||||
func NewChannel() *Channel
|
||||
type Channel[T any] struct
|
||||
func NewChannel[T any]() *Channel[T]
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -57,20 +57,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Bridge">Bridge</span>
|
||||
|
||||
<p>将多个通道链接到一个通道,直到取消上下文。</p>
|
||||
<p>将多个channel链接到一个channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
|
||||
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -85,41 +83,44 @@ import (
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
genVals := func() <-chan <-chan any {
|
||||
chanStream := make(chan (<-chan any))
|
||||
go func() {
|
||||
defer close(chanStream)
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan any, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
}
|
||||
}()
|
||||
return chanStream
|
||||
}
|
||||
c := concurrency.NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
out := make(chan (<-chan int))
|
||||
go func() {
|
||||
defer close(out)
|
||||
for i := 1; i <= 5; i++ {
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
out <- stream
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
index := 0
|
||||
for val := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
|
||||
}
|
||||
for v := range c.Bridge(ctx, genVals()) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
// 4
|
||||
// 5
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="FanIn">FanIn</span>
|
||||
|
||||
<p>将多个通道合并为一个通道,直到取消上下文</p>
|
||||
<p>将多个channel合并为一个channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
|
||||
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -134,32 +135,69 @@ import (
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
channels := make([]<-chan any, 3)
|
||||
c := concurrency.NewChannel[int]()
|
||||
channels := make([]<-chan int, 2)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
||||
}
|
||||
for i := 0; i < 2; i++ {
|
||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
|
||||
}
|
||||
|
||||
mergedChannel := c.FanIn(ctx, channels...)
|
||||
chs := c.FanIn(ctx, channels...)
|
||||
|
||||
for val := range mergedChannel {
|
||||
fmt.Println("\t%d\n", val) //1,2,1,0,0,1,0,2,2 (order not for sure)
|
||||
}
|
||||
for v := range chs {
|
||||
fmt.Println(v) //1 1 0 0 or 0 0 1 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Generate">Generate</span>
|
||||
|
||||
<p>根据传入的值,生成channel.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/concurrency"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Generate(ctx, 1, 2, 3)
|
||||
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Repeat">Repeat</span>
|
||||
|
||||
<p>返回一个chan,将参数`values`重复放入chan,直到取消上下文。</p>
|
||||
<p>返回一个channel,将参数`values`重复放入channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
|
||||
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -174,28 +212,31 @@ import (
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v) //1, 2, 1, 2, 1
|
||||
}
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="RepeatFn">RepeatFn</span>
|
||||
|
||||
<p>返回一个chan,重复执行函数fn,并将结果放入返回的chan,直到取消上下文。</p>
|
||||
<p>返回一个channel,重复执行函数fn,并将结果放入返回的channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
|
||||
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -210,31 +251,33 @@ import (
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
defer cancel()
|
||||
|
||||
fn := func() any {
|
||||
s := "a"
|
||||
return s
|
||||
}
|
||||
c := concurrency.NewChannel()
|
||||
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
fn := func() string {
|
||||
return "hello"
|
||||
}
|
||||
|
||||
for v := range dataStream {
|
||||
fmt.Println(v) //a, a, a
|
||||
}
|
||||
c := concurrency.NewChannel[string]()
|
||||
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// hello
|
||||
// hello
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Or">Or</span>
|
||||
|
||||
<p>将一个或多个通道读取到一个通道中,当任何读取通道关闭时将结束读取。</p>
|
||||
<p>将一个或多个channel读取到一个channel中,当任何读取channel关闭时将结束读取。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Or(channels ...<-chan any) <-chan any
|
||||
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -248,41 +291,36 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan interface{})
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
}()
|
||||
return c
|
||||
}
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan any)
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
}()
|
||||
return c
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
start := time.Now()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
sig(3*time.Second),
|
||||
sig(4*time.Second),
|
||||
sig(5*time.Second),
|
||||
)
|
||||
c := concurrency.NewChannel[any]()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
sig(3*time.Second),
|
||||
)
|
||||
|
||||
fmt.Println("done after %v", time.Since(start)) //1.003s
|
||||
fmt.Println("done after %v", time.Since(start)) //1.003s
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="OrDone">OrDone</span>
|
||||
|
||||
<p>将一个通道读入另一个通道,直到取消上下文。</p>
|
||||
<p>将一个channel读入另一个channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
|
||||
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -296,29 +334,31 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||
|
||||
for val := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(val) //1
|
||||
}
|
||||
for v := range c.OrDone(ctx, intStream) {
|
||||
fmt.Println(v)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Take">Take</span>
|
||||
|
||||
<p>返回一个chan,其值从另一个chan获取,直到取消上下文。</p>
|
||||
<p>返回一个channel,其值从另一个channel获取,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
|
||||
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -332,36 +372,39 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan any, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
numbers <- 4
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
numbers := make(chan int, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
numbers <- 4
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, numbers, 3)
|
||||
|
||||
for val := range intStream {
|
||||
fmt.Println(val) //1, 2, 3
|
||||
}
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Tee">Tee</span>
|
||||
|
||||
<p>将一个通道分成两个通道,直到取消上下文。</p>
|
||||
<p>将一个channel分成两个channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
|
||||
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -375,16 +418,22 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
|
||||
|
||||
out1, out2 := c.Tee(ctx, inStream)
|
||||
for val := range out1 {
|
||||
fmt.Println(val) //1
|
||||
fmt.Println(<-out2) //1
|
||||
}
|
||||
ch1, ch2 := c.Tee(ctx, intStream)
|
||||
|
||||
for v := range ch1 {
|
||||
fmt.Println(v)
|
||||
fmt.Println(<-ch2)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
// 1
|
||||
}
|
||||
```
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
- [Or](#Or)
|
||||
- [Xor](#Generate)
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [TernaryOperator](#TernaryOperator)
|
||||
|
||||
@@ -56,41 +57,52 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
// bool
|
||||
fmt.Println(condition.Bool(false)) // false
|
||||
fmt.Println(condition.Bool(true)) // true
|
||||
// bool
|
||||
result1 := condition.Bool(false)
|
||||
result2 := condition.Bool(true)
|
||||
fmt.Println(result1) // false
|
||||
fmt.Println(result2) // true
|
||||
|
||||
// integer
|
||||
fmt.Println(condition.Bool(0)) // false
|
||||
fmt.Println(condition.Bool(1)) // true
|
||||
// integer
|
||||
result3 := condition.Bool(0)
|
||||
result4 := condition.Bool(1)
|
||||
fmt.Println(result3) // false
|
||||
fmt.Println(result4) // true
|
||||
|
||||
// float
|
||||
fmt.Println(condition.Bool(0.0)) // false
|
||||
fmt.Println(condition.Bool(0.1)) // true
|
||||
// string
|
||||
result5 := condition.Bool("")
|
||||
result6 := condition.Bool(" ")
|
||||
fmt.Println(result5) // false
|
||||
fmt.Println(result6) // true
|
||||
|
||||
// string
|
||||
fmt.Println(condition.Bool("")) // false
|
||||
fmt.Println(condition.Bool(" ")) // true
|
||||
fmt.Println(condition.Bool("0")) // true
|
||||
// slice
|
||||
nums := []int{}
|
||||
result7 := condition.Bool(nums)
|
||||
|
||||
// slice
|
||||
var nums [2]int
|
||||
fmt.Println(condition.Bool(nums)) // false
|
||||
nums = [2]int{0, 1}
|
||||
fmt.Println(condition.Bool(nums)) // true
|
||||
nums = append(nums, 1, 2)
|
||||
result8 := condition.Bool(nums)
|
||||
fmt.Println(result7) // false
|
||||
fmt.Println(result8) // true
|
||||
|
||||
// map
|
||||
fmt.Println(condition.Bool(map[string]string{})) // false
|
||||
fmt.Println(condition.Bool(map[string]string{"a": "a"})) // true
|
||||
// struct
|
||||
result9 = condition.Bool(struct{}{})
|
||||
fmt.Println(result8) // false
|
||||
|
||||
// struct
|
||||
fmt.Println(condition.Bool(struct{}{})) // false
|
||||
fmt.Println(condition.Bool(time.Now())) // true
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="And">And</span>
|
||||
<p>Returns true if both a and b are truthy.</p>
|
||||
|
||||
@@ -110,17 +122,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.And(0, 1)) // false
|
||||
fmt.Println(condition.And(0, "")) // false
|
||||
fmt.Println(condition.And(0, "0")) // false
|
||||
fmt.Println(condition.And(1, "0")) // true
|
||||
fmt.Println(condition.And(0, 1)) // false
|
||||
fmt.Println(condition.And(0, "")) // false
|
||||
fmt.Println(condition.And(0, "0")) // false
|
||||
fmt.Println(condition.And(1, "0")) // true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Or">Or</span>
|
||||
<p>Returns false iff neither a nor b is truthy.</p>
|
||||
<p>Returns false if neither a nor b is truthy.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -138,17 +150,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.Or(0, "")) // false
|
||||
fmt.Println(condition.Or(0, 1)) // true
|
||||
fmt.Println(condition.Or(0, "0")) // true
|
||||
fmt.Println(condition.Or(1, "0")) // true
|
||||
fmt.Println(condition.Or(0, "")) // false
|
||||
fmt.Println(condition.Or(0, 1)) // true
|
||||
fmt.Println(condition.Or(0, "0")) // true
|
||||
fmt.Println(condition.Or(1, "0")) // true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Xor">Xor</span>
|
||||
<p>Returns true iff a or b but not both is truthy.</p>
|
||||
<p>Returns true if a or b but not both is truthy.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -166,17 +178,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.Xor(0, 0)) // false
|
||||
fmt.Println(condition.Xor(0, 1)) // true
|
||||
fmt.Println(condition.Xor(1, 0)) // true
|
||||
fmt.Println(condition.Xor(1, 1)) // false
|
||||
fmt.Println(condition.Xor(0, 0)) // false
|
||||
fmt.Println(condition.Xor(0, 1)) // true
|
||||
fmt.Println(condition.Xor(1, 0)) // true
|
||||
fmt.Println(condition.Xor(1, 1)) // false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Nor">Nor</span>
|
||||
<p>Returns true iff neither a nor b is truthy.</p>
|
||||
<p>Returns true if neither a nor b is truthy.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -194,17 +206,43 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.Nor(0, 0)) // true
|
||||
fmt.Println(condition.Nor(0, 1)) // false
|
||||
fmt.Println(condition.Nor(1, 0)) // false
|
||||
fmt.Println(condition.Nor(1, 1)) // true
|
||||
fmt.Println(condition.Nor(0, 0)) // true
|
||||
fmt.Println(condition.Nor(0, 1)) // false
|
||||
fmt.Println(condition.Nor(1, 0)) // false
|
||||
fmt.Println(condition.Nor(1, 1)) // false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Xnor">Xnor</span>
|
||||
<p>Returns true if both a and b or neither a nor b are truthy.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Xnor[T, U any](a T, b U) bool
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.Xnor(0, 0)) // true
|
||||
fmt.Println(condition.Xnor(0, 1)) // false
|
||||
fmt.Println(condition.Xnor(1, 0)) // false
|
||||
fmt.Println(condition.Xnor(1, 1)) // true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Nand">Nand</span>
|
||||
<p>Returns false iff both a and b are truthy</p>
|
||||
<p>Returns false if both a and b are truthy</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -222,10 +260,10 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.Nand(0, 0)) // true
|
||||
fmt.Println(condition.Nand(0, 1)) // true
|
||||
fmt.Println(condition.Nand(1, 0)) // true
|
||||
fmt.Println(condition.Nand(1, 1)) // false
|
||||
fmt.Println(condition.Nand(0, 0)) // true
|
||||
fmt.Println(condition.Nand(0, 1)) // true
|
||||
fmt.Println(condition.Nand(1, 0)) // true
|
||||
fmt.Println(condition.Nand(1, 1)) // false
|
||||
}
|
||||
```
|
||||
|
||||
@@ -250,10 +288,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
trueValue := "1"
|
||||
falseValue := "0"
|
||||
conditionTrue := 2 > 1
|
||||
result1 := condition.TernaryOperator(conditionTrue, 0, 1)
|
||||
|
||||
fmt.Println(condition.TernaryOperator(true, trueValue, falseValue)) // "1"
|
||||
conditionFalse := 2 > 3
|
||||
result2 := condition.TernaryOperator(conditionFalse, 0, 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
- [Or](#Or)
|
||||
- [Xor](#Generate)
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [TernaryOperator](#TernaryOperator)
|
||||
|
||||
@@ -55,41 +56,51 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
// bool
|
||||
fmt.Println(condition.Bool(false)) // false
|
||||
fmt.Println(condition.Bool(true)) // true
|
||||
// bool
|
||||
result1 := condition.Bool(false)
|
||||
result2 := condition.Bool(true)
|
||||
fmt.Println(result1) // false
|
||||
fmt.Println(result2) // true
|
||||
|
||||
// integer
|
||||
fmt.Println(condition.Bool(0)) // false
|
||||
fmt.Println(condition.Bool(1)) // true
|
||||
// integer
|
||||
result3 := condition.Bool(0)
|
||||
result4 := condition.Bool(1)
|
||||
fmt.Println(result3) // false
|
||||
fmt.Println(result4) // true
|
||||
|
||||
// float
|
||||
fmt.Println(condition.Bool(0.0)) // false
|
||||
fmt.Println(condition.Bool(0.1)) // true
|
||||
// string
|
||||
result5 := condition.Bool("")
|
||||
result6 := condition.Bool(" ")
|
||||
fmt.Println(result5) // false
|
||||
fmt.Println(result6) // true
|
||||
|
||||
// string
|
||||
fmt.Println(condition.Bool("")) // false
|
||||
fmt.Println(condition.Bool(" ")) // true
|
||||
fmt.Println(condition.Bool("0")) // true
|
||||
// slice
|
||||
nums := []int{}
|
||||
result7 := condition.Bool(nums)
|
||||
|
||||
// slice
|
||||
var nums [2]int
|
||||
fmt.Println(condition.Bool(nums)) // false
|
||||
nums = [2]int{0, 1}
|
||||
fmt.Println(condition.Bool(nums)) // true
|
||||
nums = append(nums, 1, 2)
|
||||
result8 := condition.Bool(nums)
|
||||
fmt.Println(result7) // false
|
||||
fmt.Println(result8) // true
|
||||
|
||||
// map
|
||||
fmt.Println(condition.Bool(map[string]string{})) // false
|
||||
fmt.Println(condition.Bool(map[string]string{"a": "a"})) // true
|
||||
// struct
|
||||
result9 = condition.Bool(struct{}{})
|
||||
fmt.Println(result8) // false
|
||||
|
||||
// struct
|
||||
fmt.Println(condition.Bool(struct{}{})) // false
|
||||
fmt.Println(condition.Bool(time.Now())) // true
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="And">And</span>
|
||||
<p>逻辑且操作,当切仅当a和b都为true时返回true</p>
|
||||
|
||||
@@ -109,15 +120,13 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.And(0, 1)) // false
|
||||
fmt.Println(condition.And(0, "")) // false
|
||||
fmt.Println(condition.And(0, "0")) // false
|
||||
fmt.Println(condition.And(1, "0")) // true
|
||||
fmt.Println(condition.And(0, 1)) // false
|
||||
fmt.Println(condition.And(0, "")) // false
|
||||
fmt.Println(condition.And(0, "0")) // false
|
||||
fmt.Println(condition.And(1, "0")) // true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Or">Or</span>
|
||||
<p>逻辑或操作,当切仅当a和b都为false时返回false</p>
|
||||
|
||||
@@ -137,15 +146,13 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.Or(0, "")) // false
|
||||
fmt.Println(condition.Or(0, 1)) // true
|
||||
fmt.Println(condition.Or(0, "0")) // true
|
||||
fmt.Println(condition.Or(1, "0")) // true
|
||||
fmt.Println(condition.Or(0, "")) // false
|
||||
fmt.Println(condition.Or(0, 1)) // true
|
||||
fmt.Println(condition.Or(0, "0")) // true
|
||||
fmt.Println(condition.Or(1, "0")) // true
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Xor">Xor</span>
|
||||
<p>逻辑异或操作,a和b相同返回false,a和b不相同返回true</p>
|
||||
|
||||
@@ -165,15 +172,13 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.Xor(0, 0)) // false
|
||||
fmt.Println(condition.Xor(0, 1)) // true
|
||||
fmt.Println(condition.Xor(1, 0)) // true
|
||||
fmt.Println(condition.Xor(1, 1)) // false
|
||||
fmt.Println(condition.Xor(0, 0)) // false
|
||||
fmt.Println(condition.Xor(0, 1)) // true
|
||||
fmt.Println(condition.Xor(1, 0)) // true
|
||||
fmt.Println(condition.Xor(1, 1)) // false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Nor">Nor</span>
|
||||
<p>异或的取反操作</p>
|
||||
|
||||
@@ -193,14 +198,38 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.Nor(0, 0)) // true
|
||||
fmt.Println(condition.Nor(0, 1)) // false
|
||||
fmt.Println(condition.Nor(1, 0)) // false
|
||||
fmt.Println(condition.Nor(1, 1)) // true
|
||||
fmt.Println(condition.Nor(0, 0)) // true
|
||||
fmt.Println(condition.Nor(0, 1)) // false
|
||||
fmt.Println(condition.Nor(1, 0)) // false
|
||||
fmt.Println(condition.Nor(1, 1)) // false
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Xnor">Xnor</span>
|
||||
<p>如果a和b都是真的或a和b均是假的,则返回true。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Xnor[T, U any](a T, b U) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/condition"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.Xnor(0, 0)) // true
|
||||
fmt.Println(condition.Xnor(0, 1)) // false
|
||||
fmt.Println(condition.Xnor(1, 0)) // false
|
||||
fmt.Println(condition.Xnor(1, 1)) // true
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Nand">Nand</span>
|
||||
<p>如果a和b都为真,返回false,否则返回true</p>
|
||||
@@ -221,15 +250,13 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(condition.Nand(0, 0)) // true
|
||||
fmt.Println(condition.Nand(0, 1)) // true
|
||||
fmt.Println(condition.Nand(1, 0)) // true
|
||||
fmt.Println(condition.Nand(1, 1)) // false
|
||||
fmt.Println(condition.Nand(0, 0)) // true
|
||||
fmt.Println(condition.Nand(0, 1)) // true
|
||||
fmt.Println(condition.Nand(1, 0)) // true
|
||||
fmt.Println(condition.Nand(1, 1)) // false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="TernaryOperator">TernaryOperator</span>
|
||||
<p>三元运算符</p>
|
||||
|
||||
@@ -249,10 +276,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
trueValue := "1"
|
||||
falseValue := "0"
|
||||
conditionTrue := 2 > 1
|
||||
result1 := condition.TernaryOperator(conditionTrue, 0, 1)
|
||||
|
||||
fmt.Println(condition.TernaryOperator(true, trueValue, falseValue)) // "1"
|
||||
conditionFalse := 2 > 3
|
||||
result2 := condition.TernaryOperator(conditionFalse, 0, 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -40,8 +40,6 @@ import (
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
|
||||
### <span id="ColorHexToRGB">ColorHexToRGB</span>
|
||||
<p>Convert color hex to color rgb.</p>
|
||||
|
||||
@@ -63,12 +61,14 @@ import (
|
||||
func main() {
|
||||
colorHex := "#003366"
|
||||
r, g, b := convertor.ColorHexToRGB(colorHex)
|
||||
fmt.Println(r, g, b) //0,51,102
|
||||
|
||||
fmt.Println(r, g, b)
|
||||
|
||||
// Output:
|
||||
// 0 51 102
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ColorRGBToHex">ColorRGBToHex</span>
|
||||
|
||||
<p>Convert color rgb to color hex.</p>
|
||||
@@ -92,17 +92,18 @@ func main() {
|
||||
r := 0
|
||||
g := 51
|
||||
b := 102
|
||||
colorHex := convertor.ColorRGBToHex(r, g, b)
|
||||
colorHex := ColorRGBToHex(r, g, b)
|
||||
|
||||
fmt.Println(colorHex) //#003366
|
||||
fmt.Println(colorHex)
|
||||
|
||||
// Output:
|
||||
// #003366
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToBool">ToBool</span>
|
||||
|
||||
<p>Convert string to a boolean value. Use strconv.ParseBool</p>
|
||||
<p>Convert string to bool. Use strconv.ParseBool.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -120,25 +121,29 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
v1, _ := convertor.ToBool("1")
|
||||
fmt.Println(v1) //true
|
||||
cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
|
||||
|
||||
v2, _ := convertor.ToBool("true")
|
||||
fmt.Println(v2) //true
|
||||
for i := 0; i < len(cases); i++ {
|
||||
result, _ := convertor.ToBool(cases[i])
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
v3, _ := convertor.ToBool("True")
|
||||
fmt.Println(v3) //true
|
||||
|
||||
v4, _ := convertor.ToBool("123")
|
||||
fmt.Println(v4) //false
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToBytes">ToBytes</span>
|
||||
|
||||
<p>Convert interface to byte slice.</p>
|
||||
<p>Convert value to byte slice.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -156,16 +161,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
bytesData, err := convertor.ToBytes("0")
|
||||
bytesData, err := convertor.ToBytes("abc")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(bytesData) //[]bytes{3, 4, 0, 0}
|
||||
|
||||
fmt.Println(bytesData)
|
||||
|
||||
// Output:
|
||||
// [97 98 99]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToChar">ToChar</span>
|
||||
|
||||
<p>Convert string to char slice.</p>
|
||||
@@ -186,21 +193,24 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
chars := convertor.ToChar("")
|
||||
fmt.Println(chars) //[]string{""}
|
||||
result1 := convertor.ToChar("")
|
||||
result2 := convertor.ToChar("abc")
|
||||
result3 := convertor.ToChar("1 2#3")
|
||||
|
||||
chars = convertor.ToChar("abc")
|
||||
fmt.Println(chars) //[]string{"a", "b", "c"}
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
chars = convertor.ToChar("1 2#3")
|
||||
fmt.Println(chars) //[]string{"1", " ", "2", "#", "3"}
|
||||
// Output:
|
||||
// []
|
||||
// [a b c]
|
||||
// [1 2 # 3]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="ToChannel">ToChannel</span>
|
||||
|
||||
<p>Convert a collection of elements to a read-only channels.</p>
|
||||
<p>Convert a collection of elements to a read-only channel.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -219,26 +229,24 @@ import (
|
||||
|
||||
func main() {
|
||||
ch := convertor.ToChannel([]int{1, 2, 3})
|
||||
result1 := <-ch
|
||||
result2 := <-ch
|
||||
result3 := <-ch
|
||||
|
||||
val1, _ := <-ch
|
||||
fmt.Println(val1) //1
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
val2, _ := <-ch
|
||||
fmt.Println(val2) //2
|
||||
|
||||
val3, _ := <-ch
|
||||
fmt.Println(val3) //3
|
||||
|
||||
_, ok := <-ch
|
||||
fmt.Println(ok) //false
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToFloat">ToFloat</span>
|
||||
|
||||
<p>Convert interface to a float64 value. If param is a invalid floatable, will return 0 and error. </p>
|
||||
<p>Convert value to a float64 value. If param is a invalid floatable, will return 0.0 and error. </p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -256,22 +264,33 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
v, err := convertor.ToFloat("")
|
||||
if err != nil {
|
||||
fmt.Println(err) //strconv.ParseFloat: parsing "": invalid syntax
|
||||
}
|
||||
fmt.Println(v) //0
|
||||
result1, _ := convertor.ToFloat("")
|
||||
result2, err := convertor.ToFloat("abc")
|
||||
result3, _ := convertor.ToFloat("-1")
|
||||
result4, _ := convertor.ToFloat("-.11")
|
||||
result5, _ := convertor.ToFloat("1.23e3")
|
||||
result6, _ := convertor.ToFloat(true)
|
||||
|
||||
v, _ = convertor.ToFloat("-.11")
|
||||
fmt.Println(v) //-0.11
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2, err)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 0 strconv.ParseFloat: parsing "": invalid syntax
|
||||
// -1
|
||||
// -0.11
|
||||
// 1230
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToInt">ToInt</span>
|
||||
|
||||
<p>Convert interface to a int64 value. If param is a invalid intable, will return 0 and error. </p>
|
||||
<p>Convert value to a int64 value. If param is a invalid intable, will return 0 and error. </p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -289,19 +308,27 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
v, err := convertor.ToInt("")
|
||||
if err != nil {
|
||||
fmt.Println(err) //strconv.ParseInt: parsing "": invalid syntax
|
||||
}
|
||||
fmt.Println(v) //0
|
||||
result1, _ := convertor.ToInt("123")
|
||||
result2, _ := convertor.ToInt("-123")
|
||||
result3, _ := convertor.ToInt(float64(12.3))
|
||||
result4, err := convertor.ToInt("abc")
|
||||
result5, _ := convertor.ToInt(true)
|
||||
|
||||
v, _ = convertor.ToFloat(1.12)
|
||||
fmt.Println(v) //1
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4, err)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// -123
|
||||
// 12
|
||||
// 0 strconv.ParseInt: parsing "": invalid syntax
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToJson">ToJson</span>
|
||||
|
||||
<p>Convert interface to json string. If param can't be converted, will return "" and error. </p>
|
||||
@@ -322,17 +349,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
var aMap = map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
jsonStr, _ := convertor.ToJson(aMap)
|
||||
fmt.Printf("%q", jsonStr) //"{\"a\":1,\"b\":2,\"c\":3}"
|
||||
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
result, err := ToJson(aMap)
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("%v", err)
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// {"a":1,"b":2,"c":3}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToMap">ToMap</span>
|
||||
|
||||
<p>Convert a slice or an array of structs to a map based on iteratee function. </p>
|
||||
<p>Convert a slice of structs to a map based on iteratee function. </p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -358,16 +391,18 @@ func main() {
|
||||
{name: "Hello", code: 100},
|
||||
{name: "Hi", code: 101},
|
||||
}
|
||||
|
||||
result := convertor.ToMap(messages, func(msg Message) (int, string) {
|
||||
return msg.code, msg.name
|
||||
})
|
||||
|
||||
fmt.Println(result) //{100: "Hello", 101: "Hi"}
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[100:Hello 101:Hi]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToPointer">ToPointer</span>
|
||||
|
||||
<p>Returns a pointer to passed value. </p>
|
||||
@@ -389,11 +424,13 @@ import (
|
||||
|
||||
func main() {
|
||||
result := convertor.ToPointer(123)
|
||||
fmt.Println(*result) //123
|
||||
fmt.Println(*result)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="ToString">ToString</span>
|
||||
|
||||
<p>ToString convert value to string, for number, string, []byte, will convert to string. For other type (slice, map, array, struct) will call json.Marshal</p>
|
||||
@@ -414,13 +451,33 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("%q", convertor.ToString(1)) //"1"
|
||||
fmt.Printf("%q", convertor.ToString(1.1)) //"1.1"
|
||||
fmt.Printf("%q", convertor.ToString([]int{1, 2, 3})) //"[1,2,3]"
|
||||
result1 := convertor.ToString("")
|
||||
result2 := convertor.ToString(nil)
|
||||
result3 := convertor.ToString(0)
|
||||
result4 := convertor.ToString(1.23)
|
||||
result5 := convertor.ToString(true)
|
||||
result6 := convertor.ToString(false)
|
||||
result7 := convertor.ToString([]int{1, 2, 3})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
//
|
||||
//
|
||||
// 0
|
||||
// 1.23
|
||||
// true
|
||||
// false
|
||||
// [1,2,3]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="StructToMap">StructToMap</span>
|
||||
|
||||
<p>Convert struct to map, only convert exported field, struct field tag `json` should be set.</p>
|
||||
@@ -451,12 +508,13 @@ func main() {
|
||||
}
|
||||
pm, _ := convertor.StructToMap(p)
|
||||
|
||||
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
|
||||
fmt.Println(pm)
|
||||
|
||||
// Output:
|
||||
// map[name:test]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="MapToSlice">MapToSlice</span>
|
||||
|
||||
<p>Convert a map to a slice based on iteratee function.</p>
|
||||
@@ -508,12 +566,13 @@ import (
|
||||
|
||||
func main() {
|
||||
byteData, _ := convertor.EncodeByte("abc")
|
||||
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99}
|
||||
fmt.Println(byteData)
|
||||
|
||||
// Output:
|
||||
// [6 12 0 3 97 98 99]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="DecodeByte">DecodeByte</span>
|
||||
|
||||
<p>Decode byte data to target object. target should be a pointer instance.</p>
|
||||
@@ -535,8 +594,16 @@ import (
|
||||
|
||||
func main() {
|
||||
var result string
|
||||
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||
convertor.DecodeByte(byteData, &result)
|
||||
fmt.Println(result) //"abc"
|
||||
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||
|
||||
err := convertor.DecodeByte(byteData, &result)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// abc
|
||||
}
|
||||
```
|
||||
@@ -43,16 +43,15 @@ import (
|
||||
## 文档
|
||||
|
||||
|
||||
|
||||
### <span id="ColorHexToRGB">ColorHexToRGB</span>
|
||||
<p>颜色值十六进制转rgb</p>
|
||||
<p>颜色值十六进制转rgb。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ColorHexToRGB(colorHex string) (red, green, blue int)
|
||||
```
|
||||
<b>列子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -65,22 +64,24 @@ import (
|
||||
func main() {
|
||||
colorHex := "#003366"
|
||||
r, g, b := convertor.ColorHexToRGB(colorHex)
|
||||
fmt.Println(r, g, b) //0,51,102
|
||||
|
||||
fmt.Println(r, g, b)
|
||||
|
||||
// Output:
|
||||
// 0 51 102
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ColorRGBToHex">ColorRGBToHex</span>
|
||||
|
||||
<p>颜色值rgb转十六进制</p>
|
||||
<p>颜色值rgb转十六进制。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ColorRGBToHex(red, green, blue int) string
|
||||
```
|
||||
<b>列子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -94,24 +95,25 @@ func main() {
|
||||
r := 0
|
||||
g := 51
|
||||
b := 102
|
||||
colorHex := convertor.ColorRGBToHex(r, g, b)
|
||||
colorHex := ColorRGBToHex(r, g, b)
|
||||
|
||||
fmt.Println(colorHex) //#003366
|
||||
fmt.Println(colorHex)
|
||||
|
||||
// Output:
|
||||
// #003366
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToBool">ToBool</span>
|
||||
|
||||
<p>字符串转布尔类型,使用strconv.ParseBool</p>
|
||||
<p>字符串转布尔类型,使用strconv.ParseBool。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToBool(s string) (bool, error)
|
||||
```
|
||||
<b>列子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -122,32 +124,36 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
v1, _ := convertor.ToBool("1")
|
||||
fmt.Println(v1) //true
|
||||
cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
|
||||
|
||||
v2, _ := convertor.ToBool("true")
|
||||
fmt.Println(v2) //true
|
||||
for i := 0; i < len(cases); i++ {
|
||||
result, _ := convertor.ToBool(cases[i])
|
||||
fmt.Println(result)
|
||||
}
|
||||
|
||||
v3, _ := convertor.ToBool("True")
|
||||
fmt.Println(v3) //true
|
||||
|
||||
v4, _ := convertor.ToBool("123")
|
||||
fmt.Println(v4) //false
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToBytes">ToBytes</span>
|
||||
|
||||
<p>interface转字节切片.</p>
|
||||
<p>Interface转字节切片。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToBytes(data any) ([]byte, error)
|
||||
```
|
||||
<b>列子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -158,26 +164,28 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
bytesData, err := convertor.ToBytes("0")
|
||||
bytesData, err := convertor.ToBytes("abc")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(bytesData) //[]bytes{3, 4, 0, 0}
|
||||
|
||||
fmt.Println(bytesData)
|
||||
|
||||
// Output:
|
||||
// [97 98 99]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToChar">ToChar</span>
|
||||
|
||||
<p>字符串转字符切片</p>
|
||||
<p>字符串转字符切片。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToChar(s string) []string
|
||||
```
|
||||
<b>列子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -188,29 +196,31 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
chars := convertor.ToChar("")
|
||||
fmt.Println(chars) //[]string{""}
|
||||
result1 := convertor.ToChar("")
|
||||
result2 := convertor.ToChar("abc")
|
||||
result3 := convertor.ToChar("1 2#3")
|
||||
|
||||
chars = convertor.ToChar("abc")
|
||||
fmt.Println(chars) //[]string{"a", "b", "c"}
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
chars = convertor.ToChar("1 2#3")
|
||||
fmt.Println(chars) //[]string{"1", " ", "2", "#", "3"}
|
||||
// Output:
|
||||
// []
|
||||
// [a b c]
|
||||
// [1 2 # 3]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToChannel">ToChannel</span>
|
||||
|
||||
<p>将切片转为只读channel</p>
|
||||
<p>将切片转为只读channel。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToChannel[T any](array []T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -222,33 +232,31 @@ import (
|
||||
|
||||
func main() {
|
||||
ch := convertor.ToChannel([]int{1, 2, 3})
|
||||
result1 := <-ch
|
||||
result2 := <-ch
|
||||
result3 := <-ch
|
||||
|
||||
val1, _ := <-ch
|
||||
fmt.Println(val1) //1
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
val2, _ := <-ch
|
||||
fmt.Println(val2) //2
|
||||
|
||||
val3, _ := <-ch
|
||||
fmt.Println(val3) //3
|
||||
|
||||
_, ok := <-ch
|
||||
fmt.Println(ok) //false
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToFloat">ToFloat</span>
|
||||
|
||||
<p>将interface转成float64类型,如果参数无法转换,会返回0和error</p>
|
||||
<p>将interface转成float64类型,如果参数无法转换,会返回0和error。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToFloat(value any) (float64, error)
|
||||
```
|
||||
<b>列子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -259,29 +267,40 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
v, err := convertor.ToFloat("")
|
||||
if err != nil {
|
||||
fmt.Println(err) //strconv.ParseFloat: parsing "": invalid syntax
|
||||
}
|
||||
fmt.Println(v) //0
|
||||
result1, _ := convertor.ToFloat("")
|
||||
result2, err := convertor.ToFloat("abc")
|
||||
result3, _ := convertor.ToFloat("-1")
|
||||
result4, _ := convertor.ToFloat("-.11")
|
||||
result5, _ := convertor.ToFloat("1.23e3")
|
||||
result6, _ := convertor.ToFloat(true)
|
||||
|
||||
v, _ = convertor.ToFloat("-.11")
|
||||
fmt.Println(v) //-0.11
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2, err)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// 0 strconv.ParseFloat: parsing "": invalid syntax
|
||||
// -1
|
||||
// -0.11
|
||||
// 1230
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToInt">ToInt</span>
|
||||
|
||||
<p>将interface转成int64类型,如果参数无法转换,会返回0和error</p>
|
||||
<p>将interface转成int64类型,如果参数无法转换,会返回0和error。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToInt(value any) (int64, error)
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -292,29 +311,37 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
v, err := convertor.ToInt("")
|
||||
if err != nil {
|
||||
fmt.Println(err) //strconv.ParseInt: parsing "": invalid syntax
|
||||
}
|
||||
fmt.Println(v) //0
|
||||
result1, _ := convertor.ToInt("123")
|
||||
result2, _ := convertor.ToInt("-123")
|
||||
result3, _ := convertor.ToInt(float64(12.3))
|
||||
result4, err := convertor.ToInt("abc")
|
||||
result5, _ := convertor.ToInt(true)
|
||||
|
||||
v, _ = convertor.ToFloat(1.12)
|
||||
fmt.Println(v) //1
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4, err)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// -123
|
||||
// 12
|
||||
// 0 strconv.ParseInt: parsing "": invalid syntax
|
||||
// 0
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToJson">ToJson</span>
|
||||
|
||||
<p>将interface转成json字符串,如果参数无法转换,会返回""和error</p>
|
||||
<p>将interface转成json字符串,如果参数无法转换,会返回""和error。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToJson(value any) (string, error)
|
||||
```
|
||||
<b>列子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -325,24 +352,30 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
var aMap = map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
jsonStr, _ := convertor.ToJson(aMap)
|
||||
fmt.Printf("%q", jsonStr) //"{\"a\":1,\"b\":2,\"c\":3}"
|
||||
aMap := map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
result, err := ToJson(aMap)
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("%v", err)
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// {"a":1,"b":2,"c":3}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToMap">ToMap</span>
|
||||
|
||||
<p>将切片转为map</p>
|
||||
<p>将切片转为map。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -361,26 +394,28 @@ func main() {
|
||||
{name: "Hello", code: 100},
|
||||
{name: "Hi", code: 101},
|
||||
}
|
||||
|
||||
result := convertor.ToMap(messages, func(msg Message) (int, string) {
|
||||
return msg.code, msg.name
|
||||
})
|
||||
|
||||
fmt.Println(result) //{100: "Hello", 101: "Hi"}
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[100:Hello 101:Hi]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToPointer">ToPointer</span>
|
||||
|
||||
<p>返回传入值的指针</p>
|
||||
<p>返回传入值的指针。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToPointer[T any](value T) *T
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -392,22 +427,23 @@ import (
|
||||
|
||||
func main() {
|
||||
result := convertor.ToPointer(123)
|
||||
fmt.Println(*result) //123
|
||||
fmt.Println(*result)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToString">ToString</span>
|
||||
|
||||
<p>将值转换为字符串,对于数字、字符串、[]byte,将转换为字符串。 对于其他类型(切片、映射、数组、结构)将调用 json.Marshal</p>
|
||||
<p>将值转换为字符串,对于数字、字符串、[]byte,将转换为字符串。 对于其他类型(切片、映射、数组、结构体)将调用 json.Marshal</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ToString(value any) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -418,24 +454,43 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("%q", convertor.ToString(1)) //"1"
|
||||
fmt.Printf("%q", convertor.ToString(1.1)) //"1.1"
|
||||
fmt.Printf("%q", convertor.ToString([]int{1, 2, 3})) //"[1,2,3]"
|
||||
result1 := convertor.ToString("")
|
||||
result2 := convertor.ToString(nil)
|
||||
result3 := convertor.ToString(0)
|
||||
result4 := convertor.ToString(1.23)
|
||||
result5 := convertor.ToString(true)
|
||||
result6 := convertor.ToString(false)
|
||||
result7 := convertor.ToString([]int{1, 2, 3})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
// Output:
|
||||
//
|
||||
//
|
||||
// 0
|
||||
// 1.23
|
||||
// true
|
||||
// false
|
||||
// [1,2,3]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="StructToMap">StructToMap</span>
|
||||
|
||||
<p>将struct转成map,只会转换struct中可导出的字段。struct中导出字段需要设置json tag标记</p>
|
||||
<p>将struct转成map,只会转换struct中可导出的字段。struct中导出字段需要设置json tag标记。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func StructToMap(value any) (map[string]any, error)
|
||||
```
|
||||
<b>列子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -456,22 +511,23 @@ func main() {
|
||||
}
|
||||
pm, _ := convertor.StructToMap(p)
|
||||
|
||||
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test]
|
||||
fmt.Println(pm)
|
||||
|
||||
// Output:
|
||||
// map[name:test]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="MapToSlice">MapToSlice</span>
|
||||
|
||||
<p>map中key和value执行函数iteratee后,转为切片</p>
|
||||
<p>map中key和value执行函数iteratee后,转为切片。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -491,18 +547,16 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="EncodeByte">EncodeByte</span>
|
||||
|
||||
<p>将data编码成字节切片</p>
|
||||
<p>将data编码成字节切片。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func EncodeByte(data any) ([]byte, error)
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -514,22 +568,23 @@ import (
|
||||
|
||||
func main() {
|
||||
byteData, _ := convertor.EncodeByte("abc")
|
||||
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99}
|
||||
fmt.Println(byteData)
|
||||
|
||||
// Output:
|
||||
// [6 12 0 3 97 98 99]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="DecodeByte">DecodeByte</span>
|
||||
|
||||
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例子</p>
|
||||
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func DecodeByte(data []byte, target any) error
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -541,8 +596,16 @@ import (
|
||||
|
||||
func main() {
|
||||
var result string
|
||||
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||
convertor.DecodeByte(byteData, &result)
|
||||
fmt.Println(result) //"abc"
|
||||
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||
|
||||
err := convertor.DecodeByte(byteData, &result)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// abc
|
||||
}
|
||||
```
|
||||
382
docs/cryptor.md
382
docs/cryptor.md
@@ -5,10 +5,10 @@ Package cryptor contains some functions for data encryption and decryption. Supp
|
||||
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/cryptor/aes.go](https://github.com/duke-git/lancet/blob/main/cryptor/aes.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/cryptor/des.go](https://github.com/duke-git/lancet/blob/main/cryptor/des.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/cryptor/basic.go](https://github.com/duke-git/lancet/blob/main/cryptor/basic.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/cryptor/rsa.go](https://github.com/duke-git/lancet/blob/main/cryptor/rsa.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/cryptor/encrypt.go](https://github.com/duke-git/lancet/blob/main/cryptor/encrypt.go)
|
||||
|
||||
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
@@ -61,8 +61,6 @@ import (
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
|
||||
### <span id="AesEcbEncrypt">AesEcbEncrypt</span>
|
||||
|
||||
<p>Encrypt data with key use AES ECB algorithm. Length of `key` param should be 16, 24 or 32.</p>
|
||||
@@ -83,16 +81,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
fmt.Println(string(encrypted))
|
||||
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
|
||||
decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="AesEcbDecrypt">AesEcbDecrypt</span>
|
||||
|
||||
<p>Decrypt data with key use AES ECB algorithm. Length of `key` param should be 16, 24 or 32.</p>
|
||||
@@ -113,16 +114,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
|
||||
decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key))
|
||||
fmt.Println(string(decrypted)) //hello world
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="AesCbcEncrypt">AesCbcEncrypt</span>
|
||||
|
||||
<p>Encrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p>
|
||||
@@ -143,16 +147,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
|
||||
|
||||
fmt.Println(string(encrypted))
|
||||
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
|
||||
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="AesCbcDecrypt">AesCbcDecrypt</span>
|
||||
|
||||
<p>Decrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p>
|
||||
@@ -174,16 +181,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
|
||||
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
|
||||
fmt.Println(string(decrypted)) //hello world
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="AesCtrCrypt">AesCtrCrypt</span>
|
||||
|
||||
<p>Encrypt or decrypt data with key use AES CTR algorithm. Length of `key` param should be 16, 24 or 32.</p>
|
||||
@@ -205,17 +215,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := cryptor.AesCtrCrypt([]byte(data), []byte(key))
|
||||
decrypted := cryptor.AesCtrCrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted)) //hello world
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="AesCfbEncrypt">AesCfbEncrypt</span>
|
||||
|
||||
<p>Encrypt data with key use AES CFB algorithm. Length of `key` param should be 16, 24 or 32.</p>
|
||||
@@ -237,15 +249,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key))
|
||||
fmt.Println(string(encrypted))
|
||||
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="AesCfbDecrypt">AesCfbDecrypt</span>
|
||||
|
||||
<p>Decrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p>
|
||||
@@ -267,16 +283,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key))
|
||||
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
|
||||
fmt.Println(string(decrypted)) //hello world
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="AesOfbEncrypt">AesOfbEncrypt</span>
|
||||
|
||||
<p>Enecrypt data with key use AES OFB algorithm. Length of `key` param should be 16, 24 or 32.</p>
|
||||
@@ -298,15 +317,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
|
||||
fmt.Println(string(encrypted))
|
||||
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="AesCfbDecrypt">AesOfbDecrypt</span>
|
||||
|
||||
<p>Decrypt data with key use AES OFB algorithm. Length of `key` param should be 16, 24 or 32.</p>
|
||||
@@ -328,17 +350,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefghijklmnop"
|
||||
|
||||
encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
|
||||
decrypted := cryptor.AesOfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted)) //hello world
|
||||
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Base64StdEncode">Base64StdEncode</span>
|
||||
|
||||
<p>Encode string with base64 encoding.</p>
|
||||
@@ -359,13 +383,13 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
base64Str := cryptor.Base64StdEncode("hello world")
|
||||
fmt.Println(base64Str) //aGVsbG8gd29ybGQ=
|
||||
base64Str := cryptor.Base64StdEncode("hello")
|
||||
fmt.Println(base64Str)
|
||||
|
||||
// Output:
|
||||
// aGVsbG8=
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Base64StdDecode">Base64StdDecode</span>
|
||||
|
||||
<p>Decode a base64 encoded string.</p>
|
||||
@@ -387,13 +411,14 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
str := cryptor.Base64StdDecode("aGVsbG8gd29ybGQ=")
|
||||
fmt.Println(str) //hello world
|
||||
str := cryptor.Base64StdDecode("aGVsbG8=")
|
||||
fmt.Println(str)
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="DesEcbEncrypt">DesEcbEncrypt</span>
|
||||
|
||||
<p>Encrypt data with key use DES ECB algorithm. Length of `key` param should be 8.</p>
|
||||
@@ -415,16 +440,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
|
||||
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
fmt.Println(string(encrypted))
|
||||
decrypted := cryptor.DesEcbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="DesEcbDecrypt">DesEcbDecrypt</span>
|
||||
|
||||
<p>Decrypt data with key use DES ECB algorithm. Length of `key` param should be 8.</p>
|
||||
@@ -446,17 +474,20 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byt(key)
|
||||
|
||||
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byte(key))
|
||||
|
||||
decrypted := cryptor.DesEcbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted)) //hello world
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="DesCbcEncrypt">DesCbcEncrypt</span>
|
||||
|
||||
<p>Encrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p>
|
||||
@@ -478,16 +509,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byt(key)
|
||||
|
||||
fmt.Println(string(encrypted))
|
||||
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byte(key))
|
||||
decrypted := cryptor.DesCbcDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="DesCbcDecrypt">DesCbcDecrypt</span>
|
||||
|
||||
<p>Decrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p>
|
||||
@@ -509,17 +543,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byt(key)
|
||||
decrypted := cryptor.DesCbcDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted)) //hello world
|
||||
|
||||
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byte(key))
|
||||
decrypted := cryptor.DesCbcDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="DesCtrCrypt">DesCtrCrypt</span>
|
||||
|
||||
<p>Encrypt or decrypt data with key use DES CTR algorithm. Length of `key` param should be 8.</p>
|
||||
@@ -541,17 +576,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
|
||||
encrypted := cryptor.DesCtrCrypt([]byte(data), []byte(key))
|
||||
decrypted := cryptor.DesCtrCrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted)) //hello world
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="DesCfbEncrypt">DesCfbEncrypt</span>
|
||||
|
||||
<p>Encrypt data with key use DES CFB algorithm. Length of `key` param should be 8.</p>
|
||||
@@ -573,15 +610,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byt(key)
|
||||
fmt.Println(string(encrypted))
|
||||
|
||||
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byte(key))
|
||||
decrypted := cryptor.DesCfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="DesCfbDecrypt">DesCfbDecrypt</span>
|
||||
|
||||
<p>Decrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p>
|
||||
@@ -603,16 +643,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byt(key)
|
||||
|
||||
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byte(key))
|
||||
decrypted := cryptor.DesCfbDecrypt(encrypted, []byte(key))
|
||||
fmt.Println(string(decrypted)) //hello world
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="DesOfbEncrypt">DesOfbEncrypt</span>
|
||||
|
||||
<p>Enecrypt data with key use DES OFB algorithm. Length of `key` param should be 8.</p>
|
||||
@@ -634,15 +676,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
|
||||
encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key))
|
||||
fmt.Println(string(encrypted))
|
||||
decrypted := cryptor.DesOfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="DesOfbDecrypt">DesOfbDecrypt</span>
|
||||
|
||||
<p>Decrypt data with key use DES OFB algorithm. Length of `key` param should be 8.</p>
|
||||
@@ -664,17 +709,19 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := "hello world"
|
||||
data := "hello"
|
||||
key := "abcdefgh"
|
||||
|
||||
encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key))
|
||||
decrypted := cryptor.DesOfbDecrypt(encrypted, []byte(key))
|
||||
|
||||
fmt.Println(string(decrypted)) //hello world
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="HmacMd5">HmacMd5</span>
|
||||
|
||||
<p>Get the md5 hmac hash of string.</p>
|
||||
@@ -696,13 +743,16 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := cryptor.HmacMd5("hello world", "12345"))
|
||||
fmt.Println(s) //5f4c9faaff0a1ad3007d9ddc06abe36d
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := cryptor.HmacMd5(str, key)
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// e834306eab892d872525d4918a7a639a
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="HmacSha1">HmacSha1</span>
|
||||
|
||||
<p>Get the sha1 hmac hash of string.</p>
|
||||
@@ -724,13 +774,16 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := cryptor.HmacSha1("hello world", "12345"))
|
||||
fmt.Println(s) //3826f812255d8683f051ee97346d1359234d5dbd
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := cryptor.HmacSha1(str, key)
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// 5c6a9db0cccb92e36ed0323fd09b7f936de9ace0
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="HmacSha256">HmacSha256</span>
|
||||
|
||||
<p>Get the sha256 hmac hash of string</p>
|
||||
@@ -752,13 +805,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := cryptor.HmacSha256("hello world", "12345"))
|
||||
fmt.Println(s) //9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := cryptor.HmacSha256(str, key)
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// 315bb93c4e989862ba09cb62e05d73a5f376cb36f0d786edab0c320d059fde75
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="HmacSha512">HmacSha512</span>
|
||||
|
||||
<p>Get the sha512 hmac hash of string.</p>
|
||||
@@ -780,14 +837,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := cryptor.HmacSha512("hello world", "12345"))
|
||||
fmt.Println(s)
|
||||
//5b1563ac4e9b49c9ada8ccb232588fc4f0c30fd12f756b3a0b95af4985c236ca60925253bae10ce2c6bf9af1c1679b51e5395ff3d2826c0a2c7c0d72225d4175
|
||||
str := "hello"
|
||||
key := "12345"
|
||||
|
||||
hms := cryptor.HmacSha512(str, key)
|
||||
fmt.Println(hms)
|
||||
|
||||
// Output:
|
||||
// dd8f1290a9dd23d354e2526d9a2e9ce8cffffdd37cb320800d1c6c13d2efc363288376a196c5458daf53f8e1aa6b45a6d856303d5c0a2064bff9785861d48cfc
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Md5String">Md5String</span>
|
||||
|
||||
<p>Get the md5 value of string.</p>
|
||||
@@ -809,13 +870,16 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := cryptor.Md5String("hello"))
|
||||
fmt.Println(s) //5d41402abc4b2a76b9719d911017c592
|
||||
str := "hello"
|
||||
|
||||
md5Str := cryptor.Md5String(str)
|
||||
fmt.Println(md5Str)
|
||||
|
||||
// Output:
|
||||
// 5d41402abc4b2a76b9719d911017c592
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Md5File">Md5File</span>
|
||||
|
||||
<p>Get the md5 value of file.</p>
|
||||
@@ -842,8 +906,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Sha1">Sha1</span>
|
||||
|
||||
<p>Get the sha1 value of string.</p>
|
||||
@@ -865,13 +927,16 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := cryptor.Sha1("hello world"))
|
||||
fmt.Println(s) //2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
|
||||
str := "hello"
|
||||
|
||||
result := cryptor.Sha1(str)
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Sha256">Sha256</span>
|
||||
|
||||
<p>Get the sha256 value of string.</p>
|
||||
@@ -893,13 +958,16 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := cryptor.Sha256("hello world"))
|
||||
fmt.Println(s) //b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
|
||||
str := "hello"
|
||||
|
||||
result := cryptor.Sha256(str)
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Sha512">Sha512</span>
|
||||
|
||||
<p>Get the sha512 value of string.</p>
|
||||
@@ -921,13 +989,16 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := cryptor.Sha512("hello world"))
|
||||
fmt.Println(s) //309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f
|
||||
str := "hello"
|
||||
|
||||
result := cryptor.Sha512(str)
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="GenerateRsaKey">GenerateRsaKey</span>
|
||||
|
||||
<p>Create the rsa public and private key file in current directory.</p>
|
||||
@@ -956,8 +1027,6 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="RsaEncrypt">RsaEncrypt</span>
|
||||
|
||||
<p>Encrypt data with public key file useing ras algorithm.</p>
|
||||
@@ -981,19 +1050,21 @@ import (
|
||||
func main() {
|
||||
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
data := []byte("hello world")
|
||||
|
||||
data := []byte("hello")
|
||||
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
|
||||
fmt.Println(string(decrypted)) //hello world
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="RsaDecrypt">RsaDecrypt</span>
|
||||
|
||||
<p>Decrypt data with private key file useing ras algorithm.</p>
|
||||
@@ -1017,14 +1088,17 @@ import (
|
||||
func main() {
|
||||
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
data := []byte("hello world")
|
||||
|
||||
data := []byte("hello")
|
||||
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
|
||||
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
|
||||
|
||||
fmt.Println(string(decrypted)) //hello world
|
||||
|
||||
fmt.Println(string(decrypted))
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
470
docs/datetime.md
470
docs/datetime.md
@@ -1,16 +1,18 @@
|
||||
# Datetime
|
||||
|
||||
Package datetime supports date and time format and compare.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/datetime/datetime.go](https://github.com/duke-git/lancet/blob/main/datetime/datetime.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/datetime/conversion.go](https://github.com/duke-git/lancet/blob/main/datetime/conversion.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/datetime/datetime.go](https://github.com/duke-git/lancet/blob/main/datetime/datetime.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/datetime/conversion.go](https://github.com/duke-git/lancet/blob/main/datetime/conversion.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/datetime"
|
||||
@@ -20,66 +22,67 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
- [AddDay](#AddDay)
|
||||
- [AddHour](#AddHour)
|
||||
- [AddMinute](#AddMinute)
|
||||
- [BeginOfMinute](#BeginOfMinute)
|
||||
- [BeginOfHour](#BeginOfHour)
|
||||
- [BeginOfDay](#BeginOfDay)
|
||||
- [BeginOfWeek](#BeginOfWeek)
|
||||
- [BeginOfMonth](#BeginOfMonth)
|
||||
- [BeginOfYear](#BeginOfYear)
|
||||
- [EndOfMinute](#EndOfMinute)
|
||||
- [EndOfHour](#EndOfHour)
|
||||
- [EndOfDay](#EndOfDay)
|
||||
- [EndOfWeek](#EndOfWeek)
|
||||
- [EndOfMonth](#EndOfMonth)
|
||||
- [EndOfYear](#EndOfYear)
|
||||
- [GetNowDate](#GetNowDate)
|
||||
- [GetNowTime](#GetNowTime)
|
||||
- [GetNowDateTime](#GetNowDateTime)
|
||||
- [GetZeroHourTimestamp](#GetZeroHourTimestamp)
|
||||
- [GetNightTimestamp](#GetNightTimestamp)
|
||||
- [FormatTimeToStr](#FormatTimeToStr)
|
||||
- [FormatStrToTime](#FormatStrToTime)
|
||||
- [NewUnixNow](#NewUnixNow)
|
||||
- [NewUnix](#NewUnix)
|
||||
- [NewFormat](#NewFormat)
|
||||
- [NewISO8601](#NewISO8601)
|
||||
- [ToUnix](#ToUnix)
|
||||
- [ToFormat](#ToFormat)
|
||||
- [ToFormatForTpl](#ToFormatForTpl)
|
||||
- [ToIso8601](#ToIso8601)
|
||||
|
||||
|
||||
- [AddDay](#AddDay)
|
||||
- [AddHour](#AddHour)
|
||||
- [AddMinute](#AddMinute)
|
||||
- [BeginOfMinute](#BeginOfMinute)
|
||||
- [BeginOfHour](#BeginOfHour)
|
||||
- [BeginOfDay](#BeginOfDay)
|
||||
- [BeginOfWeek](#BeginOfWeek)
|
||||
- [BeginOfMonth](#BeginOfMonth)
|
||||
- [BeginOfYear](#BeginOfYear)
|
||||
- [EndOfMinute](#EndOfMinute)
|
||||
- [EndOfHour](#EndOfHour)
|
||||
- [EndOfDay](#EndOfDay)
|
||||
- [EndOfWeek](#EndOfWeek)
|
||||
- [EndOfMonth](#EndOfMonth)
|
||||
- [EndOfYear](#EndOfYear)
|
||||
- [GetNowDate](#GetNowDate)
|
||||
- [GetNowTime](#GetNowTime)
|
||||
- [GetNowDateTime](#GetNowDateTime)
|
||||
- [GetZeroHourTimestamp](#GetZeroHourTimestamp)
|
||||
- [GetNightTimestamp](#GetNightTimestamp)
|
||||
- [FormatTimeToStr](#FormatTimeToStr)
|
||||
- [FormatStrToTime](#FormatStrToTime)
|
||||
- [NewUnixNow](#NewUnixNow)
|
||||
- [NewUnix](#NewUnix)
|
||||
- [NewFormat](#NewFormat)
|
||||
- [NewISO8601](#NewISO8601)
|
||||
- [ToUnix](#ToUnix)
|
||||
- [ToFormat](#ToFormat)
|
||||
- [ToFormatForTpl](#ToFormatForTpl)
|
||||
- [ToIso8601](#ToIso8601)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
## Note:
|
||||
1. 'format' string param in func FormatTimeToStr and FormatStrToTime function should be one of flows:
|
||||
- yyyy-mm-dd hh:mm:ss
|
||||
- yyyy-mm-dd hh:mm
|
||||
- yyyy-mm-dd hh
|
||||
- yyyy-mm-dd
|
||||
- yyyy-mm
|
||||
- mm-dd
|
||||
- dd-mm-yy hh:mm:ss
|
||||
- yyyy/mm/dd hh:mm:ss
|
||||
- yyyy/mm/dd hh:mm
|
||||
- yyyy-mm-dd hh
|
||||
- yyyy/mm/dd
|
||||
- yyyy/mm
|
||||
- mm/dd
|
||||
- dd/mm/yy hh:mm:ss
|
||||
- yyyy
|
||||
- mm
|
||||
- hh:mm:ss
|
||||
- mm:ss
|
||||
|
||||
1. 'format' string param in func FormatTimeToStr and FormatStrToTime function should be one of flows:
|
||||
|
||||
- yyyy-mm-dd hh:mm:ss
|
||||
- yyyy-mm-dd hh:mm
|
||||
- yyyy-mm-dd hh
|
||||
- yyyy-mm-dd
|
||||
- yyyy-mm
|
||||
- mm-dd
|
||||
- dd-mm-yy hh:mm:ss
|
||||
- yyyy/mm/dd hh:mm:ss
|
||||
- yyyy/mm/dd hh:mm
|
||||
- yyyy-mm-dd hh
|
||||
- yyyy/mm/dd
|
||||
- yyyy/mm
|
||||
- mm/dd
|
||||
- dd/mm/yy hh:mm:ss
|
||||
- yyyy
|
||||
- mm
|
||||
- hh:mm:ss
|
||||
- mm:ss
|
||||
|
||||
### <span id="AddDay">AddDay</span>
|
||||
|
||||
<p>Add or sub days to time.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -87,6 +90,7 @@ import (
|
||||
```go
|
||||
func AddDay(t time.Time, day int64) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -100,15 +104,24 @@ import (
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
after2Days := datetime.AddDay(now, 2)
|
||||
before2Days := datetime.AddDay(now, -2)
|
||||
|
||||
fmt.Println(after2Days, before2Days)
|
||||
tomorrow := datetime.AddDay(now, 1)
|
||||
diff1 := tomorrow.Sub(now)
|
||||
|
||||
yesterday := datetime.AddDay(now, -1)
|
||||
diff2 := yesterday.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
|
||||
// Output:
|
||||
// 24h0m0s
|
||||
// -24h0m0s
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="AddHour">AddHour</span>
|
||||
|
||||
<p>Add or sub hours to time.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -116,6 +129,7 @@ func main() {
|
||||
```go
|
||||
func AddHour(t time.Time, hour int64) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -129,14 +143,24 @@ import (
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
after2Hours := datetime.AddHour(now, 2)
|
||||
before2Hours := datetime.AddHour(now, -2)
|
||||
|
||||
fmt.Println(after2Hours, after2Hours)
|
||||
after2Hours := datetime.AddHour(now, 2)
|
||||
diff1 := after2Hours.Sub(now)
|
||||
|
||||
before2Hours := datetime.AddHour(now, -2)
|
||||
diff2 := before2Hours.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
|
||||
// Output:
|
||||
// 2h0m0s
|
||||
// -2h0m0s
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="AddMinute">AddMinute</span>
|
||||
|
||||
<p>Add or sub minutes to time.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -144,6 +168,7 @@ func main() {
|
||||
```go
|
||||
func AddMinute(t time.Time, minute int64) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -157,14 +182,24 @@ import (
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
after2Minute := datetime.AddMinute(now, 2)
|
||||
before2Minute := datetime.AddMinute(now, -2)
|
||||
|
||||
fmt.Println(after2Minute, before2Minute)
|
||||
after2Minutes := datetime.AddMinute(now, 2)
|
||||
diff1 := after2Minutes.Sub(now)
|
||||
|
||||
before2Minutes := datetime.AddMinute(now, -2)
|
||||
diff2 := before2Minutes.Sub(now)
|
||||
|
||||
fmt.Println(diff1)
|
||||
fmt.Println(diff2)
|
||||
|
||||
// Output:
|
||||
// 2m0s
|
||||
// -2m0s
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="BeginOfMinute">BeginOfMinute</span>
|
||||
|
||||
<p>Return beginning minute time of day.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -172,6 +207,7 @@ func main() {
|
||||
```go
|
||||
func BeginOfMinute(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -184,13 +220,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
|
||||
bm := datetime.BeginOfMinute(td)
|
||||
fmt.Println(bm) //2022-02-15 15:48:00 +0800 CST
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
result := datetime.BeginOfMinute(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-08 18:50:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="BeginOfHour">BeginOfHour</span>
|
||||
|
||||
<p>Return zero time of day.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -198,6 +239,7 @@ func main() {
|
||||
```go
|
||||
func BeginOfHour(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -210,13 +252,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
|
||||
bm := datetime.BeginOfHour(td)
|
||||
fmt.Println(bm) //2022-02-15 15:00:00 +0800 CST
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
result := datetime.BeginOfHour(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-08 18:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="BeginOfDay">BeginOfDay</span>
|
||||
|
||||
<p>Return begin time of day.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -224,6 +271,7 @@ func main() {
|
||||
```go
|
||||
func BeginOfDay(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -236,15 +284,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
|
||||
bm := datetime.BeginOfDay(td)
|
||||
fmt.Println(bm) //2022-02-15 00:00:00 +0800 CST
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
result := datetime.BeginOfDay(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-08 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="BeginOfWeek">BeginOfWeek</span>
|
||||
|
||||
<p>Return beginning time of week, week begin from Sunday.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -252,6 +303,7 @@ func main() {
|
||||
```go
|
||||
func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -264,15 +316,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
|
||||
bm := datetime.BeginOfWeek(td)
|
||||
fmt.Println(bm) //2022-02-13 00:00:00 +0800 CST
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
result := datetime.BeginOfWeek(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-08 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="BeginOfMonth">BeginOfMonth</span>
|
||||
|
||||
<p>Return beginning time of month</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -280,6 +335,7 @@ func main() {
|
||||
```go
|
||||
func BeginOfMonth(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -292,14 +348,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
|
||||
bm := datetime.BeginOfMonth(td)
|
||||
fmt.Println(bm) //2022-02-01 00:00:00 +0800 CST
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
result := datetime.BeginOfMonth(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="BeginOfYear">BeginOfYear</span>
|
||||
|
||||
<p>Return beginning time of year.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -307,6 +367,7 @@ func main() {
|
||||
```go
|
||||
func BeginOfYear(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -319,15 +380,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
|
||||
bm := datetime.BeginOfYear(td)
|
||||
fmt.Println(bm) //2022-01-01 00:00:00 +0800 CST
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
result := datetime.BeginOfYear(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-01 00:00:00 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="EndOfMinute">EndOfMinute</span>
|
||||
|
||||
<p>Return end time minute of day.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -335,6 +399,7 @@ func main() {
|
||||
```go
|
||||
func EndOfMinute(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -347,13 +412,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
|
||||
bm := datetime.EndOfMinute(td)
|
||||
fmt.Println(bm) //2022-02-15 15:48:59.999999999 +0800 CST
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
result := datetime.EndOfMinute(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-08 18:50:59.999999999 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="EndOfHour">EndOfHour</span>
|
||||
|
||||
<p>Return end time hour of day.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -361,6 +431,7 @@ func main() {
|
||||
```go
|
||||
func EndOfHour(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -373,13 +444,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
|
||||
bm := datetime.EndOfHour(td)
|
||||
fmt.Println(bm) //2022-02-15 15:59:59.999999999 +0800 CST
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
result := datetime.EndOfHour(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-08 18:59:59.999999999 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="EndOfDay">EndOfDay</span>
|
||||
|
||||
<p>Return end time hour of day.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -387,6 +463,7 @@ func main() {
|
||||
```go
|
||||
func EndOfDay(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -399,15 +476,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
|
||||
bm := datetime.EndOfDay(td)
|
||||
fmt.Println(bm) //2022-02-15 23:59:59.999999999 +0800 CST
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
result := datetime.EndOfDay(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-08 23:59:59.999999999 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="EndOfWeek">EndOfWeek</span>
|
||||
|
||||
<p>Return end time of week, week end with Saturday.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -415,6 +495,7 @@ func main() {
|
||||
```go
|
||||
func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -427,15 +508,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
|
||||
bm := datetime.EndOfWeek(td)
|
||||
fmt.Println(bm) //2022-02-19 23:59:59.999999999 +0800 CST
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
result := datetime.EndOfWeek(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-14 23:59:59.999999999 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="EndOfMonth">EndOfMonth</span>
|
||||
|
||||
<p>Return end time of month</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -443,6 +527,7 @@ func main() {
|
||||
```go
|
||||
func EndOfMonth(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -455,14 +540,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
|
||||
bm := datetime.EndOfMonth(td)
|
||||
fmt.Println(bm) //2022-02-28 23:59:59.999999999 +0800 CST
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
result := datetime.EndOfMonth(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-01-31 23:59:59.999999999 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="EndOfYear">EndOfYear</span>
|
||||
|
||||
<p>Return beginning time of year.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -470,6 +559,7 @@ func main() {
|
||||
```go
|
||||
func EndOfYear(t time.Time) time.Time
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -482,14 +572,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
td := time.Date(2022, 2, 15, 15, 48, 40, 112, time.Local)
|
||||
bm := datetime.EndOfYear(td)
|
||||
fmt.Println(bm) //2022-12-31 23:59:59.999999999 +0800 CST
|
||||
input := time.Date(2023, 1, 8, 18, 50, 10, 100, time.UTC)
|
||||
result := datetime.EndOfYear(input)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2023-12-31 23:59:59.999999999 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="GetNowDate">GetNowDate</span>
|
||||
|
||||
<p>Get current date string, format is yyyy-mm-dd.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -497,6 +591,7 @@ func main() {
|
||||
```go
|
||||
func GetNowDate() string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -511,12 +606,16 @@ import (
|
||||
func main() {
|
||||
now := time.Now()
|
||||
currentDate := datetime.GetNowDate()
|
||||
fmt.Println(currentDate) // 2022-01-28
|
||||
|
||||
fmt.Println(currentDate)
|
||||
|
||||
// Output:
|
||||
// 2022-01-28
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="GetNowTime">GetNowTime</span>
|
||||
|
||||
<p>Get current time string, format is hh:mm:ss.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -524,6 +623,7 @@ func main() {
|
||||
```go
|
||||
func GetNowTime() string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -538,12 +638,16 @@ import (
|
||||
func main() {
|
||||
now := time.Now()
|
||||
currentTime := datetime.GetNowTime()
|
||||
fmt.Println(currentDate) // 15:57:33
|
||||
|
||||
fmt.Println(currentTime) // 15:57:33
|
||||
|
||||
// Output:
|
||||
// 15:57:33
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="GetNowDateTime">GetNowDateTime</span>
|
||||
|
||||
<p>Get current date time string, format is yyyy-mm-dd hh:mm:ss.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -551,6 +655,7 @@ func main() {
|
||||
```go
|
||||
func GetNowDateTime() string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -565,12 +670,16 @@ import (
|
||||
func main() {
|
||||
now := time.Now()
|
||||
current := datetime.GetNowDateTime()
|
||||
fmt.Println(current) // 2022-01-28 15:59:33
|
||||
|
||||
fmt.Println(current)
|
||||
|
||||
// Output:
|
||||
// 2022-01-28 15:59:33
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span>
|
||||
|
||||
<p>Return timestamp of zero hour (timestamp of 00:00).</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -578,6 +687,7 @@ func main() {
|
||||
```go
|
||||
func GetZeroHourTimestamp() int64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -592,12 +702,16 @@ import (
|
||||
func main() {
|
||||
now := time.Now()
|
||||
zeroTime := datetime.GetZeroHourTimestamp()
|
||||
fmt.Println(zeroTime) // 1643299200
|
||||
|
||||
fmt.Println(zeroTime)
|
||||
|
||||
// Output:
|
||||
// 1643299200
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="GetNightTimestamp">GetNightTimestamp</span>
|
||||
|
||||
<p>Return timestamp of zero hour (timestamp of 23:59).</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -605,6 +719,7 @@ func main() {
|
||||
```go
|
||||
func GetNightTimestamp() int64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -619,11 +734,16 @@ import (
|
||||
func main() {
|
||||
now := time.Now()
|
||||
nightTime := datetime.GetNightTimestamp()
|
||||
fmt.Println(nightTime) // 1643385599
|
||||
|
||||
fmt.Println(nightTime)
|
||||
|
||||
// Output:
|
||||
// 1643385599
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="FormatTimeToStr">FormatTimeToStr</span>
|
||||
|
||||
<p>Format time to string, `format` param specification see note 1.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -631,6 +751,7 @@ func main() {
|
||||
```go
|
||||
func FormatTimeToStr(t time.Time, format string) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -643,14 +764,25 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
now := time.Now()
|
||||
timeStr := datetime.FormatTimeToStr(now, "yyyy/mm/dd hh:mm:ss")
|
||||
fmt.Println(timeStr) //2022/01/28 16:07:44
|
||||
t, _ := time.Parse("2006-01-02 15:04:05", "2021-01-02 16:04:08")
|
||||
|
||||
result1 := datetime.FormatTimeToStr(t, "yyyy-mm-dd hh:mm:ss")
|
||||
result2 := datetime.FormatTimeToStr(t, "yyyy-mm-dd")
|
||||
result3 := datetime.FormatTimeToStr(t, "dd-mm-yy hh:mm:ss")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 2021-01-02 16:04:08
|
||||
// 2021-01-02
|
||||
// 02-01-21 16:04:08
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="FormatStrToTime">FormatStrToTime</span>
|
||||
|
||||
<p>Format string to time, `format` param specification see note 1.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -658,6 +790,7 @@ func main() {
|
||||
```go
|
||||
func FormatStrToTime(str, format string) (time.Time, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -669,24 +802,34 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
time := datetime.FormatStrToTime("2006-01-02 15:04:05", "yyyy/mm/dd hh:mm:ss")
|
||||
fmt.Println(time)
|
||||
result1, _ := datetime.FormatStrToTime("2021-01-02 16:04:08", "yyyy-mm-dd hh:mm:ss")
|
||||
result2, _ := datetime.FormatStrToTime("2021-01-02", "yyyy-mm-dd")
|
||||
result3, _ := datetime.FormatStrToTime("02-01-21 16:04:08", "dd-mm-yy hh:mm:ss")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 2021-01-02 16:04:08 +0000 UTC
|
||||
// 2021-01-02 00:00:00 +0000 UTC
|
||||
// 2021-01-02 16:04:08 +0000 UTC
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="NewUnixNow">NewUnixNow</span>
|
||||
|
||||
<p>Return unix timestamp of current time</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type theTime struct {
|
||||
unix int64
|
||||
unix int64
|
||||
}
|
||||
func NewUnixNow() *theTime
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -699,12 +842,15 @@ import (
|
||||
|
||||
func main() {
|
||||
tm := datetime.NewUnixNow()
|
||||
fmt.Println(tm) //&{1647597438}
|
||||
fmt.Println(tm)
|
||||
|
||||
// Output:
|
||||
// &{1647597438}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="NewUnix">NewUnix</span>
|
||||
|
||||
<p>Return unix timestamp of specified int64 value.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -715,6 +861,7 @@ type theTime struct {
|
||||
}
|
||||
func NewUnix(unix int64) *theTime
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -727,13 +874,15 @@ import (
|
||||
|
||||
func main() {
|
||||
tm := datetime.NewUnix(1647597438)
|
||||
fmt.Println(tm) //&{1647597438}
|
||||
fmt.Println(tm)
|
||||
|
||||
// Output:
|
||||
// &{1647597438}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="NewFormat">NewFormat</span>
|
||||
|
||||
<p>Return unix timestamp of specified time string, t should be "yyyy-mm-dd hh:mm:ss".</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -744,6 +893,7 @@ type theTime struct {
|
||||
}
|
||||
func NewFormat(t string) (*theTime, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -756,14 +906,15 @@ import (
|
||||
|
||||
func main() {
|
||||
tm, err := datetime.NewFormat("2022-03-18 17:04:05")
|
||||
fmt.Println(tm) //&{1647594245}
|
||||
fmt.Println(tm)
|
||||
|
||||
// Output:
|
||||
// &{1647594245}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="NewISO8601">NewISO8601</span>
|
||||
|
||||
<p>Return unix timestamp of specified iso8601 time string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -774,6 +925,7 @@ type theTime struct {
|
||||
}
|
||||
func NewISO8601(iso8601 string) (*theTime, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -786,13 +938,15 @@ import (
|
||||
|
||||
func main() {
|
||||
tm, err := datetime.NewISO8601("2006-01-02T15:04:05.999Z")
|
||||
fmt.Println(tm) //&{1136214245}
|
||||
fmt.Println(tm)
|
||||
|
||||
// Output:
|
||||
// &{1136214245}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToUnix">ToUnix</span>
|
||||
|
||||
<p>Return unix timestamp.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -800,6 +954,7 @@ func main() {
|
||||
```go
|
||||
func (t *theTime) ToUnix() int64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -812,13 +967,15 @@ import (
|
||||
|
||||
func main() {
|
||||
tm := datetime.NewUnixNow()
|
||||
fmt.Println(tm.ToUnix()) //1647597438
|
||||
fmt.Println(tm.ToUnix())
|
||||
|
||||
// Output:
|
||||
// 1647597438
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToFormat">ToFormat</span>
|
||||
|
||||
<p>Return time string 'yyyy-mm-dd hh:mm:ss'.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -826,6 +983,7 @@ func main() {
|
||||
```go
|
||||
func (t *theTime) ToFormat() string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -838,13 +996,15 @@ import (
|
||||
|
||||
func main() {
|
||||
tm, _ := datetime.NewFormat("2022-03-18 17:04:05")
|
||||
fmt.Println(tm.ToFormat()) //"2022-03-18 17:04:05"
|
||||
fmt.Println(tm.ToFormat())
|
||||
|
||||
// Output:
|
||||
// 2022-03-18 17:04:05
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ToFormatForTpl">ToFormatForTpl</span>
|
||||
|
||||
<p>Return the time string which format is specified tpl.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -852,6 +1012,7 @@ func main() {
|
||||
```go
|
||||
func (t *theTime) ToFormatForTpl(tpl string) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -865,12 +1026,15 @@ import (
|
||||
func main() {
|
||||
tm, _ := datetime.NewFormat("2022-03-18 17:04:05")
|
||||
ts := tm.ToFormatForTpl("2006/01/02 15:04:05")
|
||||
fmt.Println(ts) //"2022/03/18 17:04:05"
|
||||
fmt.Println(ts)
|
||||
|
||||
// Output:
|
||||
// 2022/03/18 17:04:05
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="ToIso8601">ToIso8601</span>
|
||||
|
||||
<p>Return iso8601 time string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -878,6 +1042,7 @@ func main() {
|
||||
```go
|
||||
func (t *theTime) ToIso8601() string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -891,6 +1056,9 @@ import (
|
||||
func main() {
|
||||
tm, _ := datetime.NewISO8601("2006-01-02T15:04:05.999Z")
|
||||
ts := tm.ToIso8601()
|
||||
fmt.Println(ts) //"2006-01-02T23:04:05+08:00"
|
||||
fmt.Println(ts)
|
||||
|
||||
// Output:
|
||||
// 2006-01-02T23:04:05+08:00
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
102
docs/fileutil.md
102
docs/fileutil.md
@@ -1,15 +1,17 @@
|
||||
# Fileutil
|
||||
|
||||
Package fileutil implements some basic functions for file operations.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/fileutil/file.go](https://github.com/duke-git/lancet/blob/main/fileutil/file.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/fileutil/file.go](https://github.com/duke-git/lancet/blob/main/fileutil/file.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
@@ -19,30 +21,30 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
- [ClearFile](#ClearFile)
|
||||
- [CreateFile](#CreateFile)
|
||||
- [CreateDir](#CreateDir)
|
||||
- [CopyFile](#CopyFile)
|
||||
- [FileMode](#FileMode)
|
||||
- [MiMeType](#MiMeType)
|
||||
- [IsExist](#IsExist)
|
||||
- [IsLink](#IsLink)
|
||||
- [IsDir](#IsDir)
|
||||
- [ListFileNames](#ListFileNames)
|
||||
- [RemoveFile](#RemoveFile)
|
||||
- [ReadFileToString](#ReadFileToString)
|
||||
- [ReadFileByLine](#ReadFileByLine)
|
||||
- [Zip](#Zip)
|
||||
- [UnZip](#UnZip)
|
||||
- [UnZip](#UnZip)
|
||||
|
||||
- [ClearFile](#ClearFile)
|
||||
- [CreateFile](#CreateFile)
|
||||
- [CreateDir](#CreateDir)
|
||||
- [CopyFile](#CopyFile)
|
||||
- [FileMode](#FileMode)
|
||||
- [MiMeType](#MiMeType)
|
||||
- [IsExist](#IsExist)
|
||||
- [IsLink](#IsLink)
|
||||
- [IsDir](#IsDir)
|
||||
- [ListFileNames](#ListFileNames)
|
||||
- [RemoveFile](#RemoveFile)
|
||||
- [ReadFileToString](#ReadFileToString)
|
||||
- [ReadFileByLine](#ReadFileByLine)
|
||||
- [Zip](#Zip)
|
||||
- [UnZip](#UnZip)
|
||||
- [UnZip](#UnZip)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
|
||||
### <span id="ClearFile">ClearFile</span>
|
||||
|
||||
<p>Clear the file content, write empty string to the file.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -50,6 +52,7 @@ import (
|
||||
```go
|
||||
func ClearFile(path string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -69,6 +72,7 @@ func main() {
|
||||
```
|
||||
|
||||
### <span id="CreateFile">CreateFile</span>
|
||||
|
||||
<p>Create file in path. return true if create succeed.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -76,6 +80,7 @@ func main() {
|
||||
```go
|
||||
func CreateFile(path string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -92,9 +97,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="CreateDir">CreateDir</span>
|
||||
|
||||
<p>Create directory in absolute path. param `absPath` like /a/, /a/b/.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -102,6 +106,7 @@ func main() {
|
||||
```go
|
||||
func CreateDir(absPath string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -118,8 +123,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="CopyFile">CopyFile</span>
|
||||
|
||||
<p>Copy src file to dest file. If dest file exist will overwrite it.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -127,6 +132,7 @@ func main() {
|
||||
```go
|
||||
func CopyFile(srcFilePath string, dstFilePath string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -145,9 +151,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="FileMode">FileMode</span>
|
||||
|
||||
<p>Return file mode infomation.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -155,6 +160,7 @@ func main() {
|
||||
```go
|
||||
func FileMode(path string) (fs.FileMode, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -174,9 +180,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="MiMeType">MiMeType</span>
|
||||
|
||||
<p>Get file mime type, 'file' param's type should be string or *os.File.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -184,6 +189,7 @@ func main() {
|
||||
```go
|
||||
func MiMeType(file any) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -205,10 +211,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IsExist">IsExist</span>
|
||||
|
||||
<p>Checks if a file or directory exists.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -216,6 +220,7 @@ func main() {
|
||||
```go
|
||||
func IsExist(path string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -233,9 +238,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="IsLink">IsLink</span>
|
||||
|
||||
<p>Checks if a file is symbol link or not.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -243,6 +247,7 @@ func main() {
|
||||
```go
|
||||
func IsLink(path string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -259,16 +264,16 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="IsDir">IsDir</span>
|
||||
|
||||
<p>Checks if the path is directy or not.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func IsDir(path string) bool
|
||||
func IsDir(path string) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -288,9 +293,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ListFileNames">ListFileNames</span>
|
||||
|
||||
<p>List all file names in given path.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -298,6 +302,7 @@ func main() {
|
||||
```go
|
||||
func ListFileNames(path string) ([]string, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -314,9 +319,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="RemoveFile">RemoveFile</span>
|
||||
|
||||
<p>Remove the file of path.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -324,6 +328,7 @@ func main() {
|
||||
```go
|
||||
func RemoveFile(path string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -342,8 +347,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="ReadFileToString">ReadFileToString</span>
|
||||
|
||||
<p>Return string of file content.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -351,6 +356,7 @@ func main() {
|
||||
```go
|
||||
func ReadFileToString(path string) (string, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -374,9 +380,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ReadFileByLine">ReadFileByLine</span>
|
||||
|
||||
<p>Read file line by line, and return slice of lines</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -384,6 +389,7 @@ func main() {
|
||||
```go
|
||||
func ReadFileByLine(path string)([]string, error)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -408,9 +414,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Zip">Zip</span>
|
||||
|
||||
<p>Create a zip file of fpath, fpath could be a file or a directory.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -418,6 +423,7 @@ func main() {
|
||||
```go
|
||||
func Zip(fpath string, destPath string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -436,10 +442,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="UnZip">UnZip</span>
|
||||
|
||||
<p>Unzip the file and save it to dest path.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -447,6 +451,7 @@ func main() {
|
||||
```go
|
||||
func UnZip(zipFile string, destPath string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -464,8 +469,3 @@ func main() {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# Fileutil
|
||||
fileutil包支持文件基本操作。
|
||||
|
||||
fileutil 包支持文件基本操作。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/fileutil/file.go](https://github.com/duke-git/lancet/blob/main/fileutil/file.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/fileutil/file.go](https://github.com/duke-git/lancet/blob/main/fileutil/file.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/fileutil"
|
||||
@@ -19,29 +21,29 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
- [ClearFile](#ClearFile)
|
||||
- [CreateFile](#CreateFile)
|
||||
- [CreateDir](#CreateDir)
|
||||
- [CopyFile](#CopyFile)
|
||||
- [FileMode](#FileMode)
|
||||
- [MiMeType](#MiMeType)
|
||||
- [IsExist](#IsExist)
|
||||
- [IsLink](#IsLink)
|
||||
- [IsDir](#IsDir)
|
||||
- [ListFileNames](#ListFileNames)
|
||||
- [RemoveFile](#RemoveFile)
|
||||
- [ReadFileToString](#ReadFileToString)
|
||||
- [ReadFileByLine](#ReadFileByLine)
|
||||
- [Zip](#Zip)
|
||||
- [UnZip](#UnZip)
|
||||
|
||||
- [ClearFile](#ClearFile)
|
||||
- [CreateFile](#CreateFile)
|
||||
- [CreateDir](#CreateDir)
|
||||
- [CopyFile](#CopyFile)
|
||||
- [FileMode](#FileMode)
|
||||
- [MiMeType](#MiMeType)
|
||||
- [IsExist](#IsExist)
|
||||
- [IsLink](#IsLink)
|
||||
- [IsDir](#IsDir)
|
||||
- [ListFileNames](#ListFileNames)
|
||||
- [RemoveFile](#RemoveFile)
|
||||
- [ReadFileToString](#ReadFileToString)
|
||||
- [ReadFileByLine](#ReadFileByLine)
|
||||
- [Zip](#Zip)
|
||||
- [UnZip](#UnZip)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
|
||||
|
||||
### <span id="ClearFile">ClearFile</span>
|
||||
|
||||
<p>清空文件内容</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -49,6 +51,7 @@ import (
|
||||
```go
|
||||
func ClearFile(path string) error
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -68,6 +71,7 @@ func main() {
|
||||
```
|
||||
|
||||
### <span id="CreateFile">CreateFile</span>
|
||||
|
||||
<p>创建文件,创建成功返回true, 否则返回false</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -75,6 +79,7 @@ func main() {
|
||||
```go
|
||||
func CreateFile(path string) bool
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -91,8 +96,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="CreateDir">CreateDir</span>
|
||||
|
||||
<p>使用绝对路径创建嵌套目录,例如/a/, /a/b/</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -100,6 +105,7 @@ func main() {
|
||||
```go
|
||||
func CreateDir(absPath string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -116,16 +122,16 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="CopyFile">CopyFile</span>
|
||||
<p>拷贝文件,会覆盖原有的拷贝文件</p>
|
||||
|
||||
<p>拷贝文件,会覆盖原有的文件</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func CopyFile(srcFilePath string, dstFilePath string) error
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -144,9 +150,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="FileMode">FileMode</span>
|
||||
|
||||
<p>获取文件mode信息</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -154,6 +159,7 @@ func main() {
|
||||
```go
|
||||
func FileMode(path string) (fs.FileMode, error)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -173,9 +179,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="MiMeType">MiMeType</span>
|
||||
|
||||
<p>获取文件mime类型, 'file'参数的类型必须是string或者*os.File</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -183,6 +188,7 @@ func main() {
|
||||
```go
|
||||
func MiMeType(file any) string
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -204,10 +210,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IsExist">IsExist</span>
|
||||
|
||||
<p>判断文件或目录是否存在</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -215,6 +219,7 @@ func main() {
|
||||
```go
|
||||
func IsExist(path string) bool
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -232,9 +237,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="IsLink">IsLink</span>
|
||||
|
||||
<p>判断文件是否是符号链接</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -242,6 +246,7 @@ func main() {
|
||||
```go
|
||||
func IsLink(path string) bool
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -258,16 +263,16 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="IsDir">IsDir</span>
|
||||
<p>判断目录是否存在</p>
|
||||
|
||||
<p>判断参数是否是目录</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsDir(path string) bool
|
||||
func IsDir(path string) bool
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -287,9 +292,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ListFileNames">ListFileNames</span>
|
||||
|
||||
<p>返回目录下所有文件名</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -297,6 +301,7 @@ func main() {
|
||||
```go
|
||||
func ListFileNames(path string) ([]string, error)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -313,9 +318,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="RemoveFile">RemoveFile</span>
|
||||
|
||||
<p>删除文件</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -323,6 +327,7 @@ func main() {
|
||||
```go
|
||||
func RemoveFile(path string) error
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -341,8 +346,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="ReadFileToString">ReadFileToString</span>
|
||||
|
||||
<p>读取文件内容并返回字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -350,6 +355,7 @@ func main() {
|
||||
```go
|
||||
func ReadFileToString(path string) (string, error)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -373,9 +379,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="ReadFileByLine">ReadFileByLine</span>
|
||||
|
||||
<p>按行读取文件内容,返回字符串切片包含每一行</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -383,6 +388,7 @@ func main() {
|
||||
```go
|
||||
func ReadFileByLine(path string)([]string, error)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -407,9 +413,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Zip">Zip</span>
|
||||
|
||||
<p>zip压缩文件, fpath参数可以是文件或目录</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -417,6 +422,7 @@ func main() {
|
||||
```go
|
||||
func Zip(fpath string, destPath string) error
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -435,10 +441,8 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="UnZip">UnZip</span>
|
||||
|
||||
<p>zip解压缩文件并保存在目录中</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -446,6 +450,7 @@ func main() {
|
||||
```go
|
||||
func UnZip(zipFile string, destPath string) error
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -463,8 +468,3 @@ func main() {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# Formatter
|
||||
|
||||
formatter contains some functions for data formatting.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/formatter/formatter.go](https://github.com/duke-git/lancet/blob/main/formatter/formatter.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/formatter/formatter.go](https://github.com/duke-git/lancet/blob/main/formatter/formatter.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
@@ -19,15 +21,15 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
- [Comma](#Comma)
|
||||
|
||||
- [Comma](#Comma)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
|
||||
### <span id="Comma">Comma</span>
|
||||
|
||||
<p>Add comma to a number value by every 3 numbers from right to left. ahead by symbol char. if value is a invalid number string like "aa", return empty string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -35,6 +37,7 @@ import (
|
||||
```go
|
||||
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -46,7 +49,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(formatter.Comma("12345", "")) // "12,345"
|
||||
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67"
|
||||
result1 := formatter.Comma("123", "")
|
||||
result2 := formatter.Comma("12345", "$")
|
||||
result3 := formatter.Comma(1234567, "¥")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// $12,345
|
||||
// ¥1,234,567
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
# Formatter
|
||||
formatter格式化器包含一些数据格式化处理方法。
|
||||
|
||||
formatter 格式化器包含一些数据格式化处理方法。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/formatter/formatter.go](https://github.com/duke-git/lancet/blob/main/formatter/formatter.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/formatter/formatter.go](https://github.com/duke-git/lancet/blob/main/formatter/formatter.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/formatter"
|
||||
@@ -19,15 +21,15 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
- [Comma](#Comma)
|
||||
|
||||
- [Comma](#Comma)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
|
||||
|
||||
### <span id="Comma">Comma</span>
|
||||
|
||||
<p>用逗号每隔3位分割数字/字符串,支持前缀添加符号。参数value必须是数字或者可以转为数字的字符串, 否则返回空字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -35,6 +37,7 @@ import (
|
||||
```go
|
||||
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -46,7 +49,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(formatter.Comma("12345", "")) // "12,345"
|
||||
fmt.Println(formatter.Comma(12345.67, "¥")) // "¥12,345.67"
|
||||
result1 := formatter.Comma("123", "")
|
||||
result2 := formatter.Comma("12345", "$")
|
||||
result3 := formatter.Comma(1234567, "¥")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// $12,345
|
||||
// ¥1,234,567
|
||||
}
|
||||
```
|
||||
|
||||
285
docs/function.md
285
docs/function.md
@@ -1,16 +1,18 @@
|
||||
# Function
|
||||
|
||||
Package function can control the flow of function execution and support part of functional programming.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/function.go](https://github.com/duke-git/lancet/blob/main/function/function.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/watcher.go](https://github.com/duke-git/lancet/blob/main/function/watcher.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/function.go](https://github.com/duke-git/lancet/blob/main/function/function.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/watcher.go](https://github.com/duke-git/lancet/blob/main/function/watcher.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Usage:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
@@ -20,22 +22,22 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [Curry](#Curry)
|
||||
- [Compose](#Compose)
|
||||
- [Debounced](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
- [Pipeline](#Pipeline)
|
||||
- [Watcher](#Watcher)
|
||||
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [CurryFn](#CurryFn)
|
||||
- [Compose](#Compose)
|
||||
- [Debounced](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
- [Pipeline](#Pipeline)
|
||||
- [Watcher](#Watcher)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
|
||||
### <span id="After">After</span>
|
||||
|
||||
<p>Creates a function that invokes given func once it's called n or more times.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -43,6 +45,7 @@ import (
|
||||
```go
|
||||
func After(n int, fn any) func(args ...any) []reflect.Value
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -54,33 +57,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
arr := []string{"a", "b"}
|
||||
f := function.After(len(arr), func(i int) int {
|
||||
fmt.Println("last print")
|
||||
return i
|
||||
})
|
||||
fn := function.After(2, func() {
|
||||
fmt.Println("hello")
|
||||
})
|
||||
|
||||
type cb func(args ...any) []reflect.Value
|
||||
print := func(i int, s string, fn cb) {
|
||||
fmt.Printf("arr[%d] is %s \n", i, s)
|
||||
fn(i)
|
||||
}
|
||||
fn()
|
||||
fn()
|
||||
|
||||
fmt.Println("arr is", arr)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
print(i, arr[i], f)
|
||||
}
|
||||
|
||||
//output:
|
||||
// arr is [a b]
|
||||
// arr[0] is a
|
||||
// arr[1] is b
|
||||
// last print
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Before">Before</span>
|
||||
|
||||
<p>creates a function that invokes func once it's called less than n times.</p>
|
||||
@@ -90,6 +78,7 @@ func main() {
|
||||
```go
|
||||
func Before(n int, fn any) func(args ...any) []reflect.Value
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -102,39 +91,32 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
arr := []string{"a", "b", "c", "d", "e"}
|
||||
f := function.Before(3, func(i int) int {
|
||||
return i
|
||||
})
|
||||
fn := function.Before(2, func() {
|
||||
fmt.Println("hello")
|
||||
})
|
||||
|
||||
var res []int64
|
||||
type cb func(args ...any) []reflect.Value
|
||||
appendStr := func(i int, s string, fn cb) {
|
||||
v := fn(i)
|
||||
res = append(res, v[0].Int())
|
||||
}
|
||||
fn()
|
||||
fn()
|
||||
fn()
|
||||
fn()
|
||||
|
||||
for i := 0; i < len(arr); i++ {
|
||||
appendStr(i, arr[i], f)
|
||||
}
|
||||
|
||||
expected := []int64{0, 1, 2, 2, 2}
|
||||
fmt.Println(res) // 0, 1, 2, 2, 2
|
||||
// Output:
|
||||
// hello
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CurryFn">CurryFn</span>
|
||||
|
||||
|
||||
### <span id="Curry">Curry</span>
|
||||
|
||||
<p>Make a curry function.</p>
|
||||
<p>Make curry function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
type Fn func(...any) any
|
||||
func (f Fn) Curry(i any) func(...any) any
|
||||
type CurryFn[T any] func(...T) T
|
||||
func (cf CurryFn[T]) New(val T) func(...T) T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -147,19 +129,23 @@ import (
|
||||
|
||||
func main() {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
var addCurry function.Fn = func(values ...any) any {
|
||||
return add(values[0].(int), values[1].(int))
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
result := add1(2)
|
||||
fmt.Println(result) //3
|
||||
return a + b
|
||||
}
|
||||
|
||||
var addCurry function.CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
result := add1(2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Compose">Compose</span>
|
||||
|
||||
<p>Compose the function list from right to left, then return the composed function.</p>
|
||||
@@ -167,8 +153,9 @@ func main() {
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Compose(fnList ...func(...any) any) func(...any) any
|
||||
func Compose[T any](fnList ...func(...T) T) func(...T) T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -180,22 +167,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
add1 := func(v ...any) any {
|
||||
return v[0].(int) + 1
|
||||
}
|
||||
add2 := func(v ...any) any {
|
||||
return v[0].(int) + 2
|
||||
}
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
transform := function.Compose(toUpper, toLower)
|
||||
|
||||
add3 := function.Compose(add1, add2)
|
||||
result := add3(1)
|
||||
result := transform("aBCde")
|
||||
|
||||
fmt.Println(result) //4
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// ABCDE
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Debounced">Debounced</span>
|
||||
|
||||
<p>Creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.</p>
|
||||
@@ -205,6 +193,7 @@ func main() {
|
||||
```go
|
||||
func Debounced(fn func(), duration time.Duration) func()
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -217,27 +206,34 @@ import (
|
||||
|
||||
func main() {
|
||||
count := 0
|
||||
add := func() {
|
||||
count++
|
||||
}
|
||||
|
||||
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
add := func() {
|
||||
count++
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Println(count) //1
|
||||
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
|
||||
|
||||
function.debouncedAdd()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Println(count) //2
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
debouncedAdd()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Delay">Delay</span>
|
||||
|
||||
<p>Invoke function after delayed time.</p>
|
||||
@@ -247,6 +243,7 @@ func main() {
|
||||
```go
|
||||
func Delay(delay time.Duration, fn any, args ...any)
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -258,15 +255,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
var print = func(s string) {
|
||||
fmt.Println(count) //test delay
|
||||
}
|
||||
function.Delay(2*time.Second, print, "test delay")
|
||||
var print = func(s string) {
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
function.Delay(2*time.Second, print, "hello")
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Schedule">Schedule</span>
|
||||
|
||||
<p>Invoke function every duration time, until close the returned bool chan.</p>
|
||||
@@ -276,6 +275,7 @@ func main() {
|
||||
```go
|
||||
func Schedule(d time.Duration, fn any, args ...any) chan bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -287,20 +287,24 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
var res []string
|
||||
appendStr := func(s string) {
|
||||
res = append(res, s)
|
||||
}
|
||||
count := 0
|
||||
|
||||
stop := function.Schedule(1*time.Second, appendStr, "*")
|
||||
time.Sleep(5 * time.Second)
|
||||
close(stop)
|
||||
increase := func() {
|
||||
count++
|
||||
}
|
||||
|
||||
fmt.Println(res) //[* * * * *]
|
||||
stop := function.Schedule(2*time.Second, increase)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
close(stop)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Pipeline">Pipeline</span>
|
||||
|
||||
<p>Pipeline takes a list of functions and returns a function whose param will be passed into
|
||||
@@ -311,6 +315,7 @@ the functions one by one.</p>
|
||||
```go
|
||||
func Pipeline[T any](funcs ...func(T) T) func(T) T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -323,22 +328,26 @@ import (
|
||||
|
||||
func main() {
|
||||
addOne := func(x int) int {
|
||||
return x + 1
|
||||
}
|
||||
double := func(x int) int {
|
||||
return 2 * x
|
||||
}
|
||||
square := func(x int) int {
|
||||
return x * x
|
||||
}
|
||||
return x + 1
|
||||
}
|
||||
double := func(x int) int {
|
||||
return 2 * x
|
||||
}
|
||||
square := func(x int) int {
|
||||
return x * x
|
||||
}
|
||||
|
||||
f := Pipeline(addOne, double, square)
|
||||
fn := function.Pipeline(addOne, double, square)
|
||||
|
||||
fmt.Println(f(2)) //36
|
||||
result := fn(2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 36
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Watcher">Watcher</span>
|
||||
|
||||
<p>Watcher is used for record code excution time. can start/stop/reset the watch timer. get the elapsed time of function execution.</p>
|
||||
@@ -347,15 +356,17 @@ func main() {
|
||||
|
||||
```go
|
||||
type Watcher struct {
|
||||
startTime int64
|
||||
stopTime int64
|
||||
excuting bool
|
||||
startTime int64
|
||||
stopTime int64
|
||||
excuting bool
|
||||
}
|
||||
func NewWatcher() *Watcher
|
||||
func (w *Watcher) Start() //start the watcher
|
||||
func (w *Watcher) Stop() //stop the watcher
|
||||
func (w *Watcher) Reset() //reset the watcher
|
||||
func (w *Watcher) GetElapsedTime() time.Duration //get the elapsed time of function execution
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -367,34 +378,28 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := &function.Watcher{}
|
||||
w.Start()
|
||||
w := function.NewWatcher()
|
||||
|
||||
longRunningTask()
|
||||
w.Start()
|
||||
|
||||
fmt.Println(w.excuting) //true
|
||||
longRunningTask()
|
||||
|
||||
w.Stop()
|
||||
fmt.Println(w.excuting) //true
|
||||
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
fmt.Println(eapsedTime)
|
||||
w.Stop()
|
||||
|
||||
w.Reset()
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
|
||||
fmt.Println(w.excuting) //false
|
||||
fmt.Println(eapsedTime)
|
||||
|
||||
fmt.Println(w.startTime) //0
|
||||
fmt.Println(w.stopTime) //0
|
||||
w.Reset()
|
||||
}
|
||||
|
||||
func longRunningTask() {
|
||||
var slice []int64
|
||||
for i := 0; i < 10000000; i++ {
|
||||
slice = append(slice, int64(i))
|
||||
}
|
||||
var slice []int64
|
||||
for i := 0; i < 10000000; i++ {
|
||||
slice = append(slice, int64(i))
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
# Function
|
||||
function函数包控制函数执行流程,包含部分函数式编程。
|
||||
|
||||
function 函数包控制函数执行流程,包含部分函数式编程。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/function.go](https://github.com/duke-git/lancet/blob/main/function/function.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/watcher.go](https://github.com/duke-git/lancet/blob/main/function/watcher.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/function.go](https://github.com/duke-git/lancet/blob/main/function/function.go)
|
||||
- [https://github.com/duke-git/lancet/blob/main/function/watcher.go](https://github.com/duke-git/lancet/blob/main/function/watcher.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/function"
|
||||
@@ -20,22 +22,22 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [Curry](#Curry)
|
||||
- [Compose](#Compose)
|
||||
- [Debounced](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
- [Pipeline](#Pipeline)
|
||||
- [Watcher](#Watcher)
|
||||
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [CurryFn](#CurryFn)
|
||||
- [Compose](#Compose)
|
||||
- [Debounced](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
- [Pipeline](#Pipeline)
|
||||
- [Watcher](#Watcher)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 文档
|
||||
|
||||
|
||||
|
||||
### <span id="After">After</span>
|
||||
|
||||
<p>创建一个函数,当他被调用n或更多次之后将马上触发fn</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -43,6 +45,7 @@ import (
|
||||
```go
|
||||
func After(n int, fn any) func(args ...any) []reflect.Value
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -54,33 +57,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
arr := []string{"a", "b"}
|
||||
f := function.After(len(arr), func(i int) int {
|
||||
fmt.Println("last print")
|
||||
return i
|
||||
})
|
||||
fn := function.After(2, func() {
|
||||
fmt.Println("hello")
|
||||
})
|
||||
|
||||
type cb func(args ...any) []reflect.Value
|
||||
print := func(i int, s string, fn cb) {
|
||||
fmt.Printf("arr[%d] is %s \n", i, s)
|
||||
fn(i)
|
||||
}
|
||||
fn()
|
||||
fn()
|
||||
|
||||
fmt.Println("arr is", arr)
|
||||
for i := 0; i < len(arr); i++ {
|
||||
print(i, arr[i], f)
|
||||
}
|
||||
|
||||
//output:
|
||||
// arr is [a b]
|
||||
// arr[0] is a
|
||||
// arr[1] is b
|
||||
// last print
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Before">Before</span>
|
||||
|
||||
<p>创建一个函数,调用次数不超过n次,之后再调用这个函数,将返回一次最后调用fn的结果</p>
|
||||
@@ -90,6 +78,7 @@ func main() {
|
||||
```go
|
||||
func Before(n int, fn any) func(args ...any) []reflect.Value
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -102,38 +91,32 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
arr := []string{"a", "b", "c", "d", "e"}
|
||||
f := function.Before(3, func(i int) int {
|
||||
return i
|
||||
})
|
||||
fn := function.Before(2, func() {
|
||||
fmt.Println("hello")
|
||||
})
|
||||
|
||||
var res []int64
|
||||
type cb func(args ...any) []reflect.Value
|
||||
appendStr := func(i int, s string, fn cb) {
|
||||
v := fn(i)
|
||||
res = append(res, v[0].Int())
|
||||
}
|
||||
fn()
|
||||
fn()
|
||||
fn()
|
||||
fn()
|
||||
|
||||
for i := 0; i < len(arr); i++ {
|
||||
appendStr(i, arr[i], f)
|
||||
}
|
||||
|
||||
fmt.Println(res) // 0, 1, 2, 2, 2
|
||||
// Output:
|
||||
// hello
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CurryFn">CurryFn</span>
|
||||
|
||||
|
||||
### <span id="Curry">Curry</span>
|
||||
|
||||
<p>创建一个柯里化的函数</p>
|
||||
<p>创建柯里化函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type Fn func(...any) any
|
||||
func (f Fn) Curry(i any) func(...any) any
|
||||
type CurryFn[T any] func(...T) T
|
||||
func (cf CurryFn[T]) New(val T) func(...T) T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -145,29 +128,34 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
var addCurry function.Fn = func(values ...any) any {
|
||||
return add(values[0].(int), values[1].(int))
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
result := add1(2)
|
||||
fmt.Println(result) //3
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
|
||||
var addCurry function.CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
result := add1(2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Compose">Compose</span>
|
||||
|
||||
<p>从右至左组合函数列表fnList, 返回组合后的函数</p>
|
||||
<p>从右至左组合函数列表fnList,返回组合后的函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Compose(fnList ...func(...any) any) func(...any) any
|
||||
func Compose[T any](fnList ...func(...T) T) func(...T) T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -179,31 +167,33 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
add1 := func(v ...any) any {
|
||||
return v[0].(int) + 1
|
||||
}
|
||||
add2 := func(v ...any) any {
|
||||
return v[0].(int) + 2
|
||||
}
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
transform := function.Compose(toUpper, toLower)
|
||||
|
||||
add3 := function.Compose(add1, add2)
|
||||
result := add3(1)
|
||||
result := transform("aBCde")
|
||||
|
||||
fmt.Println(result) //4
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// ABCDE
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Debounced">Debounced</span>
|
||||
|
||||
<p>创建一个 debounced 函数,该函数延迟调用 fn 直到自上次调用 debounced 函数后等待持续时间过去。</p>
|
||||
<p>创建一个debounced函数,该函数延迟调用fn直到自上次调用debounced函数后等待持续时间过去。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Debounced(fn func(), duration time.Duration) func()
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -215,28 +205,35 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
count := 0
|
||||
add := func() {
|
||||
count++
|
||||
}
|
||||
count := 0
|
||||
|
||||
add := func() {
|
||||
count++
|
||||
}
|
||||
|
||||
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
function.debouncedAdd()
|
||||
debouncedAdd := function.Debounced(add, 50*time.Microsecond)
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Println(count) //1
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
|
||||
function.debouncedAdd()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Println(count) //2
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
debouncedAdd()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Delay">Delay</span>
|
||||
|
||||
<p>延迟delay时间后调用函数</p>
|
||||
@@ -246,6 +243,7 @@ func main() {
|
||||
```go
|
||||
func Delay(delay time.Duration, fn any, args ...any)
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -257,15 +255,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
var print = func(s string) {
|
||||
fmt.Println(count) //test delay
|
||||
}
|
||||
function.Delay(2*time.Second, print, "test delay")
|
||||
var print = func(s string) {
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
function.Delay(2*time.Second, print, "hello")
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Schedule">Schedule</span>
|
||||
|
||||
<p>每次持续时间调用函数,直到关闭返回的 bool chan</p>
|
||||
@@ -275,6 +275,7 @@ func main() {
|
||||
```go
|
||||
func Schedule(d time.Duration, fn any, args ...any) chan bool
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -286,21 +287,24 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
var res []string
|
||||
appendStr := func(s string) {
|
||||
res = append(res, s)
|
||||
}
|
||||
count := 0
|
||||
|
||||
stop := function.Schedule(1*time.Second, appendStr, "*")
|
||||
time.Sleep(5 * time.Second)
|
||||
close(stop)
|
||||
increase := func() {
|
||||
count++
|
||||
}
|
||||
|
||||
fmt.Println(res) //[* * * * *]
|
||||
stop := function.Schedule(2*time.Second, increase)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
close(stop)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Pipeline">Pipeline</span>
|
||||
|
||||
<p>执行函数pipeline.</p>
|
||||
@@ -310,6 +314,7 @@ func main() {
|
||||
```go
|
||||
func Pipeline[T any](funcs ...func(T) T) func(T) T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -322,40 +327,45 @@ import (
|
||||
|
||||
func main() {
|
||||
addOne := func(x int) int {
|
||||
return x + 1
|
||||
}
|
||||
double := func(x int) int {
|
||||
return 2 * x
|
||||
}
|
||||
square := func(x int) int {
|
||||
return x * x
|
||||
}
|
||||
return x + 1
|
||||
}
|
||||
double := func(x int) int {
|
||||
return 2 * x
|
||||
}
|
||||
square := func(x int) int {
|
||||
return x * x
|
||||
}
|
||||
|
||||
f := Pipeline(addOne, double, square)
|
||||
fn := function.Pipeline(addOne, double, square)
|
||||
|
||||
fmt.Println(f(2)) //36
|
||||
result := fn(2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 36
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Watcher">Watcher</span>
|
||||
|
||||
<p>Watcher 用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。 </p>
|
||||
<p>Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
type Watcher struct {
|
||||
startTime int64
|
||||
stopTime int64
|
||||
excuting bool
|
||||
startTime int64
|
||||
stopTime int64
|
||||
excuting bool
|
||||
}
|
||||
func NewWatcher() *Watcher
|
||||
func (w *Watcher) Start() //start the watcher
|
||||
func (w *Watcher) Stop() //stop the watcher
|
||||
func (w *Watcher) Reset() //reset the watcher
|
||||
func (w *Watcher) GetElapsedTime() time.Duration //get the elapsed time of function execution
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -367,34 +377,29 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := &function.Watcher{}
|
||||
w.Start()
|
||||
w := function.NewWatcher()
|
||||
|
||||
longRunningTask()
|
||||
w.Start()
|
||||
|
||||
fmt.Println(w.excuting) //true
|
||||
longRunningTask()
|
||||
|
||||
w.Stop()
|
||||
fmt.Println(w.excuting) //true
|
||||
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
fmt.Println(eapsedTime)
|
||||
w.Stop()
|
||||
|
||||
w.Reset()
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
|
||||
fmt.Println(w.excuting) //false
|
||||
fmt.Println(eapsedTime)
|
||||
|
||||
w.Reset()
|
||||
|
||||
fmt.Println(w.startTime) //0
|
||||
fmt.Println(w.stopTime) //0
|
||||
}
|
||||
|
||||
func longRunningTask() {
|
||||
var slice []int64
|
||||
for i := 0; i < 10000000; i++ {
|
||||
slice = append(slice, int64(i))
|
||||
}
|
||||
var slice []int64
|
||||
for i := 0; i < 10000000; i++ {
|
||||
slice = append(slice, int64(i))
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
303
docs/maputil.md
303
docs/maputil.md
@@ -1,16 +1,17 @@
|
||||
# Maputil
|
||||
|
||||
Package maputil includes some functions to manipulate map.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/maputil/map.go](https://github.com/duke-git/lancet/blob/main/maputil/map.go)
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/maputil/map.go](https://github.com/duke-git/lancet/blob/main/maputil/map.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Example:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
@@ -20,22 +21,22 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
- [ForEach](#ForEach)
|
||||
- [Filter](#Filter)
|
||||
- [Intersect](#Intersect)
|
||||
- [Keys](#Keys)
|
||||
- [Merge](#Merge)
|
||||
- [Minus](#Minus)
|
||||
- [Values](#Values)
|
||||
- [IsDisjoint](#IsDisjoint)
|
||||
|
||||
- [ForEach](#ForEach)
|
||||
- [Filter](#Filter)
|
||||
- [Intersect](#Intersect)
|
||||
- [Keys](#Keys)
|
||||
- [Merge](#Merge)
|
||||
- [Minus](#Minus)
|
||||
- [Values](#Values)
|
||||
- [IsDisjoint](#IsDisjoint)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
|
||||
### <span id="ForEach">ForEach</span>
|
||||
|
||||
<p>Executes iteratee funcation for every key and value pair in map.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -43,6 +44,7 @@ import (
|
||||
```go
|
||||
func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V))
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -54,26 +56,28 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
}
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
}
|
||||
|
||||
var sum int
|
||||
var sum int
|
||||
|
||||
maputil.ForEach(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
fmt.Println(sum) // 10
|
||||
maputil.ForEach(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
|
||||
fmt.Println(sum)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Filter">Filter</span>
|
||||
|
||||
<p>Iterates over map, return a new map contains all key and value pairs pass the predicate function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -81,6 +85,7 @@ func main() {
|
||||
```go
|
||||
func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -92,29 +97,32 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
"e": 5,
|
||||
}
|
||||
isEven := func(_ string, value int) bool {
|
||||
return value%2 == 0
|
||||
}
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
"e": 5,
|
||||
}
|
||||
isEven := func(_ string, value int) bool {
|
||||
return value%2 == 0
|
||||
}
|
||||
|
||||
maputil.Filter(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
res := maputil.Filter(m, isEven)
|
||||
fmt.Println(res) // map[string]int{"b": 2, "d": 4,}
|
||||
maputil.Filter(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
|
||||
result := maputil.Filter(m, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[b:2 d:4]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Intersect">Intersect</span>
|
||||
|
||||
<p>Iterates over maps, return a new map of key and value pairs in all given maps.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -122,6 +130,7 @@ func main() {
|
||||
```go
|
||||
func Intersect[K comparable, V any](maps ...map[K]V) map[K]V
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -133,37 +142,42 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 6,
|
||||
"d": 7,
|
||||
}
|
||||
m2 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 6,
|
||||
"d": 7,
|
||||
}
|
||||
|
||||
m3 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 9,
|
||||
"e": 9,
|
||||
}
|
||||
m3 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 9,
|
||||
"e": 9,
|
||||
}
|
||||
|
||||
fmt.Println(maputil.Intersect(m1)) // map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
result1 := maputil.Intersect(m1)
|
||||
result2 := maputil.Intersect(m1, m2)
|
||||
result3 := maputil.Intersect(m1, m2, m3)
|
||||
|
||||
fmt.Println(maputil.Intersect(m1, m2)) // map[string]int{"a": 1, "b": 2}
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
fmt.Println(maputil.Intersect(m1, m2, m3)) // map[string]int{"a": 1}
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
// map[a:1 b:2]
|
||||
// map[a:1]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Keys">Keys</span>
|
||||
|
||||
<p>Returns a slice of the map's keys.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -171,6 +185,7 @@ func main() {
|
||||
```go
|
||||
func Keys[K comparable, V any](m map[K]V) []K
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -182,24 +197,26 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
|
||||
keys := maputil.Keys(m)
|
||||
sort.Ints(keys)
|
||||
fmt.Println(keys) // []int{1, 2, 3, 4, 5}
|
||||
keys := maputil.Keys(m)
|
||||
sort.Ints(keys)
|
||||
|
||||
fmt.Println(keys)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Merge">Merge</span>
|
||||
|
||||
<p>Merge maps, next key will overwrite previous key.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -207,6 +224,7 @@ func main() {
|
||||
```go
|
||||
func Merge[K comparable, V any](maps ...map[K]V) map[K]V
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -218,22 +236,26 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := map[int]string{
|
||||
1: "a",
|
||||
2: "b",
|
||||
}
|
||||
m2 := map[int]string{
|
||||
1: "1",
|
||||
3: "2",
|
||||
}
|
||||
fmt.Println(maputil.Merge(m1, m2)) // map[int]string{1:"1", 2:"b", 3:"2",}
|
||||
m1 := map[int]string{
|
||||
1: "a",
|
||||
2: "b",
|
||||
}
|
||||
m2 := map[int]string{
|
||||
1: "1",
|
||||
3: "2",
|
||||
}
|
||||
|
||||
result := maputil.Merge(m1, m2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[1:c 2:b 3:d]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Minus">Minus</span>
|
||||
|
||||
<p>Creates an map of whose key in mapA but not in mapB.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -241,6 +263,7 @@ func main() {
|
||||
```go
|
||||
func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -252,25 +275,29 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"a": 11,
|
||||
"b": 22,
|
||||
"d": 33,
|
||||
}
|
||||
m2 := map[string]int{
|
||||
"a": 11,
|
||||
"b": 22,
|
||||
"d": 33,
|
||||
}
|
||||
|
||||
result := maputil.Minus(m1, m2)
|
||||
|
||||
fmt.Println(maputil.Minus(m1, m2)) //map[string]int{"c": 3}
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[c:3]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Values">Values</span>
|
||||
|
||||
<p>Returns a slice of the map's values.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -278,6 +305,7 @@ func main() {
|
||||
```go
|
||||
func Values[K comparable, V any](m map[K]V) []V
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -289,22 +317,26 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
|
||||
values := maputil.Values(m)
|
||||
sort.Strings(values)
|
||||
values := maputil.Values(m)
|
||||
sort.Strings(values)
|
||||
|
||||
fmt.Println(values) // []string{"a", "a", "b", "c", "d"}
|
||||
fmt.Println(values)
|
||||
|
||||
// Output:
|
||||
// [a a b c d]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="IsDisjoint">IsDisjoint</span>
|
||||
|
||||
<p>Checks two maps are disjoint if they have no keys in common</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -312,6 +344,7 @@ func main() {
|
||||
```go
|
||||
func IsDisjoint[K comparable, V any](mapA, mapB map[K]V) bool
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -323,30 +356,28 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
m2 := map[string]int{
|
||||
"d": 22,
|
||||
}
|
||||
|
||||
m3 := map[int]string{
|
||||
6: "a",
|
||||
}
|
||||
m3 := map[string]int{
|
||||
"a": 22,
|
||||
}
|
||||
|
||||
ok := maputil.IsDisjoint(m2, m1)
|
||||
fmt.Println(ok) // false
|
||||
result1 := maputil.IsDisjoint(m1, m2)
|
||||
result2 := maputil.IsDisjoint(m1, m3)
|
||||
|
||||
ok = maputil.IsDisjoint(m2, m3)
|
||||
fmt.Println(ok) // true
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
# Maputil
|
||||
maputil包包括一些操作map的函数。
|
||||
|
||||
maputil 包包括一些操作 map 的函数。
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/maputil/map.go](https://github.com/duke-git/lancet/blob/main/maputil/map.go)
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/maputil/map.go](https://github.com/duke-git/lancet/blob/main/maputil/map.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/maputil"
|
||||
@@ -20,22 +21,22 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录:
|
||||
- [ForEach](#ForEach)
|
||||
- [Filter](#Filter)
|
||||
- [Intersect](#Intersect)
|
||||
- [Keys](#Keys)
|
||||
- [Merge](#Merge)
|
||||
- [Minus](#Minus)
|
||||
- [Values](#Values)
|
||||
- [IsDisjoint](#IsDisjoint)
|
||||
|
||||
- [ForEach](#ForEach)
|
||||
- [Filter](#Filter)
|
||||
- [Intersect](#Intersect)
|
||||
- [Keys](#Keys)
|
||||
- [Merge](#Merge)
|
||||
- [Minus](#Minus)
|
||||
- [Values](#Values)
|
||||
- [IsDisjoint](#IsDisjoint)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## API文档:
|
||||
|
||||
|
||||
## API 文档:
|
||||
|
||||
### <span id="ForEach">ForEach</span>
|
||||
|
||||
<p>对map中的每对key和value执行iteratee函数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -43,6 +44,7 @@ import (
|
||||
```go
|
||||
func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V))
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -54,26 +56,28 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
}
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
}
|
||||
|
||||
var sum int
|
||||
var sum int
|
||||
|
||||
maputil.ForEach(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
fmt.Println(sum) // 10
|
||||
maputil.ForEach(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
|
||||
fmt.Println(sum)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Filter">Filter</span>
|
||||
|
||||
<p>迭代map中的每对key和value, 返回符合predicate函数的key, value</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -81,6 +85,7 @@ func main() {
|
||||
```go
|
||||
func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -92,29 +97,32 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
"e": 5,
|
||||
}
|
||||
isEven := func(_ string, value int) bool {
|
||||
return value%2 == 0
|
||||
}
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
"e": 5,
|
||||
}
|
||||
isEven := func(_ string, value int) bool {
|
||||
return value%2 == 0
|
||||
}
|
||||
|
||||
maputil.Filter(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
res := maputil.Filter(m, isEven)
|
||||
fmt.Println(res) // map[string]int{"b": 2, "d": 4,}
|
||||
maputil.Filter(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
|
||||
result := Filter(m, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[b:2 d:4]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Intersect">Intersect</span>
|
||||
|
||||
<p>多个map的交集操作</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -122,6 +130,7 @@ func main() {
|
||||
```go
|
||||
func Intersect[K comparable, V any](maps ...map[K]V) map[K]V
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -133,37 +142,42 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 6,
|
||||
"d": 7,
|
||||
}
|
||||
m2 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 6,
|
||||
"d": 7,
|
||||
}
|
||||
|
||||
m3 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 9,
|
||||
"e": 9,
|
||||
}
|
||||
m3 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 9,
|
||||
"e": 9,
|
||||
}
|
||||
|
||||
fmt.Println(maputil.Intersect(m1)) // map[string]int{"a": 1, "b": 2, "c": 3}
|
||||
result1 := maputil.Intersect(m1)
|
||||
result2 := maputil.Intersect(m1, m2)
|
||||
result3 := maputil.Intersect(m1, m2, m3)
|
||||
|
||||
fmt.Println(maputil.Intersect(m1, m2)) // map[string]int{"a": 1, "b": 2}
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
fmt.Println(maputil.Intersect(m1, m2, m3)) // map[string]int{"a": 1}
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
// map[a:1 b:2]
|
||||
// map[a:1]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Keys">Keys</span>
|
||||
|
||||
<p>返回map中所有key的切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -171,6 +185,7 @@ func main() {
|
||||
```go
|
||||
func Keys[K comparable, V any](m map[K]V) []K
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -182,24 +197,26 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
|
||||
keys := maputil.Keys(m)
|
||||
sort.Ints(keys)
|
||||
fmt.Println(keys) // []int{1, 2, 3, 4, 5}
|
||||
keys := maputil.Keys(m)
|
||||
sort.Ints(keys)
|
||||
|
||||
fmt.Println(keys)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Merge">Merge</span>
|
||||
|
||||
<p>合并多个maps, 相同的key会被后来的key覆盖</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -207,6 +224,7 @@ func main() {
|
||||
```go
|
||||
func Merge[K comparable, V any](maps ...map[K]V) map[K]V
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -218,21 +236,26 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := map[int]string{
|
||||
1: "a",
|
||||
2: "b",
|
||||
}
|
||||
m2 := map[int]string{
|
||||
1: "1",
|
||||
3: "2",
|
||||
}
|
||||
fmt.Println(maputil.Merge(m1, m2)) // map[int]string{1:"1", 2:"b", 3:"2",}
|
||||
m1 := map[int]string{
|
||||
1: "a",
|
||||
2: "b",
|
||||
}
|
||||
m2 := map[int]string{
|
||||
1: "1",
|
||||
3: "2",
|
||||
}
|
||||
|
||||
result := maputil.Merge(m1, m2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[1:c 2:b 3:d]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Minus">Minus</span>
|
||||
|
||||
<p>返回一个map,其中的key存在于mapA,不存在于mapB.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -240,6 +263,7 @@ func main() {
|
||||
```go
|
||||
func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -251,25 +275,29 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"a": 11,
|
||||
"b": 22,
|
||||
"d": 33,
|
||||
}
|
||||
m2 := map[string]int{
|
||||
"a": 11,
|
||||
"b": 22,
|
||||
"d": 33,
|
||||
}
|
||||
|
||||
fmt.Println(maputil.Minus(m1, m2)) //map[string]int{"c": 3}
|
||||
result := maputil.Minus(m1, m2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[c:3]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Values">Values</span>
|
||||
|
||||
<p>返回map中所有value的切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -277,6 +305,7 @@ func main() {
|
||||
```go
|
||||
func Values[K comparable, V any](m map[K]V) []V
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -288,23 +317,24 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
|
||||
values := maputil.Values(m)
|
||||
sort.Strings(values)
|
||||
values := maputil.Values(m)
|
||||
sort.Strings(values)
|
||||
|
||||
fmt.Println(values) // []string{"a", "a", "b", "c", "d"}
|
||||
// Output:
|
||||
// [a a b c d]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="IsDisjoint">IsDisjoint</span>
|
||||
|
||||
<p>验证两个map是否具有不同的key</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -312,6 +342,7 @@ func main() {
|
||||
```go
|
||||
func IsDisjoint[K comparable, V any](mapA, mapB map[K]V) bool
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -323,30 +354,28 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
m2 := map[string]int{
|
||||
"d": 22,
|
||||
}
|
||||
|
||||
m3 := map[int]string{
|
||||
6: "a",
|
||||
}
|
||||
m3 := map[string]int{
|
||||
"a": 22,
|
||||
}
|
||||
|
||||
ok := maputil.IsDisjoint(m2, m1)
|
||||
fmt.Println(ok) // false
|
||||
result1 := maputil.IsDisjoint(m1, m2)
|
||||
result2 := maputil.IsDisjoint(m1, m3)
|
||||
|
||||
ok = maputil.IsDisjoint(m2, m3)
|
||||
fmt.Println(ok) // true
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
299
docs/mathutil.md
299
docs/mathutil.md
@@ -1,16 +1,17 @@
|
||||
# Mathutil
|
||||
|
||||
Package mathutil implements some functions for math calculation.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Source:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go)
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Example:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
@@ -20,26 +21,26 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Index
|
||||
- [Average](#Average)
|
||||
- [Exponent](#Exponent)
|
||||
- [Fibonacci](#Fibonacci)
|
||||
- [Factorial](#Factorial)
|
||||
- [Max](#Max)
|
||||
- [MaxBy](#MaxBy)
|
||||
- [Min](#Min)
|
||||
- [MinBy](#MaxBy)
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
- [TruncRound](#TruncRound)
|
||||
|
||||
- [Average](#Average)
|
||||
- [Exponent](#Exponent)
|
||||
- [Fibonacci](#Fibonacci)
|
||||
- [Factorial](#Factorial)
|
||||
- [Max](#Max)
|
||||
- [MaxBy](#MaxBy)
|
||||
- [Min](#Min)
|
||||
- [MinBy](#MaxBy)
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
- [TruncRound](#TruncRound)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
|
||||
### <span id="Average">Average</span>
|
||||
|
||||
<p>Return average value of numbers. Maybe call RoundToFloat to round result.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -47,6 +48,7 @@ import (
|
||||
```go
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -58,16 +60,22 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Average(0, 0)) //0
|
||||
fmt.Println(mathutil.Average(1, 1)) //1
|
||||
avg := mathutil.Average(1.2, 1.4) //1.2999999998
|
||||
roundAvg := mmathutil.RoundToFloat(avg, 1) // 1.3
|
||||
result1 := mathutil.Average(1, 2)
|
||||
|
||||
avg := mathutil.Average(1.2, 1.4)
|
||||
result2 := mathutil.RoundToFloat(avg, 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Exponent">Exponent</span>
|
||||
|
||||
<p>Calculate x to the nth power.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -75,6 +83,7 @@ func main() {
|
||||
```go
|
||||
func Exponent(x, n int64) int64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -86,15 +95,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Exponent(10, 0)) //1
|
||||
fmt.Println(mathutil.Exponent(10, 1)) //10
|
||||
fmt.Println(mathutil.Exponent(10, 2)) //100
|
||||
result1 := mathutil.Exponent(10, 0)
|
||||
result2 := mathutil.Exponent(10, 1)
|
||||
result3 := mathutil.Exponent(10, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 10
|
||||
// 100
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Fibonacci">Fibonacci</span>
|
||||
|
||||
<p>Calculate the nth number of fibonacci sequence.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -102,6 +119,7 @@ func main() {
|
||||
```go
|
||||
func Fibonacci(first, second, n int) int
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -113,17 +131,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 1)) //1
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 2)) //1
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 3)) //2
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 4)) //3
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 5)) //5
|
||||
result1 := mathutil.Fibonacci(1, 1, 1)
|
||||
result2 := mathutil.Fibonacci(1, 1, 2)
|
||||
result3 := mathutil.Fibonacci(1, 1, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 5
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Factorial">Factorial</span>
|
||||
|
||||
<p>Calculate the factorial of x.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -131,6 +155,7 @@ func main() {
|
||||
```go
|
||||
func Factorial(x uint) uint
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -142,16 +167,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Factorial(0)) //1
|
||||
fmt.Println(mathutil.Factorial(1)) //1
|
||||
fmt.Println(mathutil.Factorial(2)) //2
|
||||
fmt.Println(mathutil.Factorial(3)) //6
|
||||
result1 := mathutil.Factorial(1)
|
||||
result2 := mathutil.Factorial(2)
|
||||
result3 := mathutil.Factorial(3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 6
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Max">Max</span>
|
||||
|
||||
<p>Return max value of numbers.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -159,6 +191,7 @@ func main() {
|
||||
```go
|
||||
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -170,23 +203,28 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Max(0, 0)) //0
|
||||
fmt.Println(mathutil.Max(1, 2, 3)) //3
|
||||
fmt.Println(mathutil.Max(1.2, 1.4, 1.1, 1.4)) //1.4
|
||||
result1 := mathutil.Max(1, 2, 3)
|
||||
result2 := mathutil.Max(1.2, 1.4, 1.1, 1.4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 1.4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="MaxBy">MaxBy</span>
|
||||
|
||||
<p>Return the maximum value of a slice using the given comparator function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func MaxBy[T any](slice []T, comparator func(T, T) bool) T
|
||||
func MaxBy[T any](slice []T, comparator func(T, T) bool) T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -198,33 +236,39 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
res1 := mathutil.MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
fmt.Println(res1) //abc
|
||||
result1 := mathutil.MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
|
||||
res2 := mathutil.MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
fmt.Println(res2) //abd
|
||||
result2 := mathutil.MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
|
||||
res3 := mathutil.MaxBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
fmt.Println(res3) //“”
|
||||
result3 := mathutil.MaxBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// abc
|
||||
// abd
|
||||
//
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
<p>Return min value of numbers.</p>
|
||||
|
||||
<p>Return the minimum value of numbers.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -236,22 +280,28 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Min(0, 0)) //0
|
||||
fmt.Println(mathutil.Min(1, 2, 3)) //1
|
||||
fmt.Println(mathutil.Min(1.2, 1.4, 1.1, 1.4)) //1.1
|
||||
result1 := mathutil.Min(1, 2, 3)
|
||||
result2 := mathutil.Min(1.2, 1.4, 1.1, 1.4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="MinBy">MinBy</span>
|
||||
|
||||
<p>Return the minimum value of a slice using the given comparator function.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func MinBy[T any](slice []T, comparator func(T, T) bool) T
|
||||
func MinBy[T any](slice []T, comparator func(T, T) bool) T
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -263,27 +313,31 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
res1 := mathutil.MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
fmt.Println(res1) //a
|
||||
result1 := mathutil.MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
|
||||
res2 := mathutil.MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
fmt.Println(res2) //ab
|
||||
result2 := mathutil.MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
|
||||
res3 := mathutil.MinBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
fmt.Println(res3) //“”
|
||||
result3 := mathutil.MinBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// a
|
||||
// ab
|
||||
//
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Percent">Percent</span>
|
||||
|
||||
<p>calculate the percentage of val to total, retain n decimal places.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -291,6 +345,7 @@ func main() {
|
||||
```go
|
||||
func Percent(val, total float64, n int) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -302,14 +357,20 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
||||
result1 := mathutil.Percent(1, 2, 2)
|
||||
result2 := mathutil.Percent(0.1, 0.3, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0.5
|
||||
// 0.33
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="RoundToFloat">RoundToFloat</span>
|
||||
|
||||
<p>Round float up to n decimal places.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -317,6 +378,7 @@ func main() {
|
||||
```go
|
||||
func RoundToFloat(x float64, n int) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -328,18 +390,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.RoundToFloat(0, 0)) //0
|
||||
fmt.Println(mathutil.RoundToFloat(0, 1)) //0
|
||||
fmt.Println(mathutil.RoundToFloat(0.124, 2)) //0.12
|
||||
fmt.Println(mathutil.RoundToFloat(0.125, 2)) //0.13
|
||||
fmt.Println(mathutil.RoundToFloat(0.125, 3)) //0.125
|
||||
result1 := mathutil.RoundToFloat(0.124, 2)
|
||||
result2 := mathutil.RoundToFloat(0.125, 2)
|
||||
result3 := mathutil.RoundToFloat(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.12
|
||||
// 0.13
|
||||
// 0.125
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="RoundToString">RoundToString</span>
|
||||
|
||||
<p>Round float up to n decimal places. will return string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -347,6 +414,7 @@ func main() {
|
||||
```go
|
||||
func RoundToString(x float64, n int) string
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -358,17 +426,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.RoundToString(0, 0)) //"0"
|
||||
fmt.Println(mathutil.RoundToString(0, 1)) //"0.0:
|
||||
fmt.Println(mathutil.RoundToString(0.124, 2)) //"0.12"
|
||||
fmt.Println(mathutil.RoundToString(0.125, 2)) //"0.13"
|
||||
fmt.Println(mathutil.RoundToString(0.125, 3)) //"0.125"
|
||||
result1 := mathutil.RoundToString(0.124, 2)
|
||||
result2 := mathutil.RoundToString(0.125, 2)
|
||||
result3 := mathutil.RoundToString(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.12
|
||||
// 0.13
|
||||
// 0.125
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="TruncRound">TruncRound</span>
|
||||
|
||||
<p>Round float off n decimal places.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
@@ -376,6 +450,7 @@ func main() {
|
||||
```go
|
||||
func TruncRound(x float64, n int) float64
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
@@ -387,13 +462,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.TruncRound(0, 0)) //0
|
||||
fmt.Println(mathutil.TruncRound(0, 1)) //0
|
||||
fmt.Println(mathutil.TruncRound(0.124, 2)) //0.12
|
||||
fmt.Println(mathutil.TruncRound(0.125, 2)) //0.12
|
||||
fmt.Println(mathutil.TruncRound(0.125, 3)) //0.125
|
||||
result1 := mathutil.TruncRound(0.124, 2)
|
||||
result2 := mathutil.TruncRound(0.125, 2)
|
||||
result3 := mathutil.TruncRound(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.12
|
||||
// 0.12
|
||||
// 0.125
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
# Mathutil
|
||||
mathutil包实现了一些数学计算的函数.
|
||||
|
||||
mathutil 包实现了一些数学计算的函数.
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 源码:
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go)
|
||||
|
||||
- [https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go](https://github.com/duke-git/lancet/blob/main/mathutil/mathutil.go)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 用法:
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/duke-git/lancet/v2/mathutil"
|
||||
@@ -20,25 +21,26 @@ import (
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## 目录
|
||||
- [Average](#Average)
|
||||
- [Exponent](#Exponent)
|
||||
- [Fibonacci](#Fibonacci)
|
||||
- [Factorial](#Factorial)
|
||||
- [Max](#Max)
|
||||
- [MaxBy](#MaxBy)
|
||||
- [Min](#Min)
|
||||
- [MinBy](#MaxBy)
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
- [TruncRound](#TruncRound)
|
||||
|
||||
- [Average](#Average)
|
||||
- [Exponent](#Exponent)
|
||||
- [Fibonacci](#Fibonacci)
|
||||
- [Factorial](#Factorial)
|
||||
- [Max](#Max)
|
||||
- [MaxBy](#MaxBy)
|
||||
- [Min](#Min)
|
||||
- [MinBy](#MaxBy)
|
||||
- [Percent](#Percent)
|
||||
- [RoundToFloat](#RoundToFloat)
|
||||
- [RoundToString](#RoundToString)
|
||||
- [TruncRound](#TruncRound)
|
||||
|
||||
<div STYLE="page-break-after: always;"></div>
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
### <span id="Average">Average</span>
|
||||
|
||||
<p>计算平均数. 可能需要对结果调用RoundToFloat方法四舍五入</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -46,6 +48,7 @@ import (
|
||||
```go
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -57,15 +60,22 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Average(0, 0)) //0
|
||||
fmt.Println(mathutil.Average(1, 1)) //1
|
||||
avg := mathutil.Average(1.2, 1.4) //1.2999999998
|
||||
roundAvg := mmathutil.RoundToFloat(avg, 1) // 1.3
|
||||
result1 := mathutil.Average(1, 2)
|
||||
|
||||
avg := mathutil.Average(1.2, 1.4)
|
||||
result2 := mathutil.RoundToFloat(avg, 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.3
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Exponent">Exponent</span>
|
||||
|
||||
<p>指数计算(x的n次方)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -73,6 +83,7 @@ func main() {
|
||||
```go
|
||||
func Exponent(x, n int64) int64
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -84,15 +95,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Exponent(10, 0)) //1
|
||||
fmt.Println(mathutil.Exponent(10, 1)) //10
|
||||
fmt.Println(mathutil.Exponent(10, 2)) //100
|
||||
result1 := mathutil.Exponent(10, 0)
|
||||
result2 := mathutil.Exponent(10, 1)
|
||||
result3 := mathutil.Exponent(10, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 10
|
||||
// 100
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Fibonacci">Fibonacci</span>
|
||||
|
||||
<p>计算斐波那契数列的第n个数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -100,6 +119,7 @@ func main() {
|
||||
```go
|
||||
func Fibonacci(first, second, n int) int
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -111,17 +131,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 1)) //1
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 2)) //1
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 3)) //2
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 4)) //3
|
||||
fmt.Println(mathutil.Fibonacci(1, 1, 5)) //5
|
||||
result1 := mathutil.Fibonacci(1, 1, 1)
|
||||
result2 := mathutil.Fibonacci(1, 1, 2)
|
||||
result3 := mathutil.Fibonacci(1, 1, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 5
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Factorial">Factorial</span>
|
||||
|
||||
<p>计算阶乘</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -129,6 +155,7 @@ func main() {
|
||||
```go
|
||||
func Factorial(x uint) uint
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -140,15 +167,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Factorial(0)) //1
|
||||
fmt.Println(mathutil.Factorial(1)) //1
|
||||
fmt.Println(mathutil.Factorial(2)) //2
|
||||
fmt.Println(mathutil.Factorial(3)) //6
|
||||
result1 := mathutil.Factorial(1)
|
||||
result2 := mathutil.Factorial(2)
|
||||
result3 := mathutil.Factorial(3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 6
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Max">Max</span>
|
||||
|
||||
<p>返回参数中的最大数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -156,6 +191,7 @@ func main() {
|
||||
```go
|
||||
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -167,22 +203,28 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Max(0, 0)) //0
|
||||
fmt.Println(mathutil.Max(1, 2, 3)) //3
|
||||
fmt.Println(mathutil.Max(1.2, 1.4, 1.1, 1.4)) //1.4
|
||||
result1 := mathutil.Max(1, 2, 3)
|
||||
result2 := mathutil.Max(1.2, 1.4, 1.1, 1.4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 1.4
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="MaxBy">MaxBy</span>
|
||||
|
||||
<p>使用给定的比较器函数返回切片的最大值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MaxBy[T any](slice []T, comparator func(T, T) bool) T
|
||||
func MaxBy[T any](slice []T, comparator func(T, T) bool) T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -194,27 +236,31 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
res1 := mathutil.MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
fmt.Println(res1) //abc
|
||||
result1 := mathutil.MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
|
||||
res2 := mathutil.MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
fmt.Println(res2) //abd
|
||||
result2 := mathutil.MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
|
||||
res3 := mathutil.MaxBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
fmt.Println(res3) //“”
|
||||
result3 := mathutil.MaxBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// abc
|
||||
// abd
|
||||
//
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
|
||||
<p>返回参数中的最小数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -222,6 +268,7 @@ func main() {
|
||||
```go
|
||||
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -233,22 +280,28 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Min(0, 0)) //0
|
||||
fmt.Println(mathutil.Min(1, 2, 3)) //1
|
||||
fmt.Println(mathutil.Min(1.2, 1.4, 1.1, 1.4)) //1.1
|
||||
result1 := mathutil.Min(1, 2, 3)
|
||||
result2 := mathutil.Min(1.2, 1.4, 1.1, 1.4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.1
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="MinBy">MinBy</span>
|
||||
|
||||
<p>使用给定的比较器函数返回切片的最小值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func MinBy[T any](slice []T, comparator func(T, T) bool) T
|
||||
func MinBy[T any](slice []T, comparator func(T, T) bool) T
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -260,27 +313,31 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
res1 := mathutil.MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
fmt.Println(res1) //a
|
||||
result1 := mathutil.MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
|
||||
res2 := mathutil.MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
fmt.Println(res2) //ab
|
||||
result2 := mathutil.MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
|
||||
res3 := mathutil.MinBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
fmt.Println(res3) //“”
|
||||
result3 := mathutil.MinBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// a
|
||||
// ab
|
||||
//
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Percent">Percent</span>
|
||||
|
||||
<p>计算百分比,保留n位小数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -288,6 +345,7 @@ func main() {
|
||||
```go
|
||||
func Percent(val, total float64, n int) float64
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -299,14 +357,20 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
||||
result1 := mathutil.Percent(1, 2, 2)
|
||||
result2 := mathutil.Percent(0.1, 0.3, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0.5
|
||||
// 0.33
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="RoundToFloat">RoundToFloat</span>
|
||||
|
||||
<p>四舍五入,保留n位小数</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -314,6 +378,7 @@ func main() {
|
||||
```go
|
||||
func RoundToFloat(x float64, n int) float64
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -325,18 +390,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.RoundToFloat(0, 0)) //0
|
||||
fmt.Println(mathutil.RoundToFloat(0, 1)) //0
|
||||
fmt.Println(mathutil.RoundToFloat(0.124, 2)) //0.12
|
||||
fmt.Println(mathutil.RoundToFloat(0.125, 2)) //0.13
|
||||
fmt.Println(mathutil.RoundToFloat(0.125, 3)) //0.125
|
||||
result1 := mathutil.RoundToFloat(0.124, 2)
|
||||
result2 := mathutil.RoundToFloat(0.125, 2)
|
||||
result3 := mathutil.RoundToFloat(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.12
|
||||
// 0.13
|
||||
// 0.125
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="RoundToString">RoundToString</span>
|
||||
|
||||
<p>四舍五入,保留n位小数,返回字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -344,6 +414,7 @@ func main() {
|
||||
```go
|
||||
func RoundToString(x float64, n int) string
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -355,17 +426,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.RoundToString(0, 0)) //"0"
|
||||
fmt.Println(mathutil.RoundToString(0, 1)) //"0.0:
|
||||
fmt.Println(mathutil.RoundToString(0.124, 2)) //"0.12"
|
||||
fmt.Println(mathutil.RoundToString(0.125, 2)) //"0.13"
|
||||
fmt.Println(mathutil.RoundToString(0.125, 3)) //"0.125"
|
||||
result1 := mathutil.RoundToString(0.124, 2)
|
||||
result2 := mathutil.RoundToString(0.125, 2)
|
||||
result3 := mathutil.RoundToString(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.12
|
||||
// 0.13
|
||||
// 0.125
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="TruncRound">TruncRound</span>
|
||||
|
||||
<p>截短n位小数(不进行四舍五入)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
@@ -373,6 +450,7 @@ func main() {
|
||||
```go
|
||||
func TruncRound(x float64, n int) float64
|
||||
```
|
||||
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
@@ -384,13 +462,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.TruncRound(0, 0)) //0
|
||||
fmt.Println(mathutil.TruncRound(0, 1)) //0
|
||||
fmt.Println(mathutil.TruncRound(0.124, 2)) //0.12
|
||||
fmt.Println(mathutil.TruncRound(0.125, 2)) //0.12
|
||||
fmt.Println(mathutil.TruncRound(0.125, 3)) //0.125
|
||||
result1 := mathutil.TruncRound(0.124, 2)
|
||||
result2 := mathutil.TruncRound(0.125, 2)
|
||||
result3 := mathutil.TruncRound(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.12
|
||||
// 0.12
|
||||
// 0.125
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -531,7 +531,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="StructToUrlValues">StructToUrlValues</span>
|
||||
<p>将结构体转为url values, 仅转化结构体导出字段并且包含`json` tag.</p>
|
||||
<p>将结构体转为url values, 仅转化结构体导出字段并且包含`json` tag</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
|
||||
@@ -319,7 +319,7 @@ func main() {
|
||||
|
||||
### <span id="DifferenceBy">DifferenceBy</span>
|
||||
|
||||
<p>在slice和comparedSlice中的每个元素调用iteratee函数,并比较它们的返回值,如果不想等返回在slice中对应的值</p>
|
||||
<p>将两个slice中的每个元素调用iteratee函数,并比较它们的返回值,如果不相等返回在slice中对应的值</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -349,7 +349,7 @@ func main() {
|
||||
|
||||
### <span id="DifferenceWith">DifferenceWith</span>
|
||||
|
||||
<p>DifferenceWith 接受比较器,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定</p>
|
||||
<p>接受比较器函数,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -379,7 +379,7 @@ func main() {
|
||||
|
||||
### <span id="DeleteAt">DeleteAt</span>
|
||||
|
||||
<p>删除切片中从开始索引到结束索引-1的元素</p>
|
||||
<p>删除切片中指定开始索引到结束索引的元素</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -407,7 +407,7 @@ func main() {
|
||||
|
||||
### <span id="Drop">Drop</span>
|
||||
|
||||
<p>创建一个切片,当 n > 0 时从开头删除 n 个元素,或者当 n < 0 时从结尾删除 n 个元素</p>
|
||||
<p>创建一个切片,当n > 0时从开头删除n个元素,或者当n < 0时从结尾删除n个元素</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -1442,7 +1442,7 @@ func main() {
|
||||
|
||||
### <span id="Union">Union</span>
|
||||
|
||||
<p>合并多个切片.</p>
|
||||
<p>合并多个切片</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
|
||||
545
docs/strutil.md
545
docs/strutil.md
@@ -37,6 +37,7 @@ import (
|
||||
- [SnakeCase](#SnakeCase)
|
||||
- [UpperSnakeCase](#UpperSnakeCase)
|
||||
- [SplitEx](#SplitEx)
|
||||
- [Substring](#Substring)
|
||||
- [Wrap](#Wrap)
|
||||
- [Unwrap](#Unwrap)
|
||||
|
||||
@@ -47,7 +48,7 @@ import (
|
||||
|
||||
|
||||
### <span id="After">After</span>
|
||||
<p>Creates substring in source string after position when char first appear.</p>
|
||||
<p>Returns the substring after the first occurrence of a specified string in the source string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -63,21 +64,29 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.After("lancet", "")
|
||||
fmt.Println(s1) //lancet
|
||||
result1 := strutil.After("foo", "")
|
||||
result2 := strutil.After("foo", "foo")
|
||||
result3 := strutil.After("foo/bar", "foo")
|
||||
result4 := strutil.After("foo/bar", "/")
|
||||
result5 := strutil.After("foo/bar/baz", "/")
|
||||
|
||||
s2 := strutil.After("github.com/test/lancet", "/")
|
||||
fmt.Println(s2) //test/lancet
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
s3 := strutil.After("github.com/test/lancet", "test")
|
||||
fmt.Println(s3) // /lancet
|
||||
// Output:
|
||||
// foo
|
||||
//
|
||||
// /bar
|
||||
// bar
|
||||
// bar/baz
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="AfterLast">AfterLast</span>
|
||||
<p>Creates substring in source string after position when char last appear.</p>
|
||||
<p>Returns the substring after the last occurrence of a specified string in the source string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -93,22 +102,29 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.AfterLast("lancet", "")
|
||||
fmt.Println(s1) //lancet
|
||||
result1 := strutil.AfterLast("foo", "")
|
||||
result2 := strutil.AfterLast("foo", "foo")
|
||||
result3 := strutil.AfterLast("foo/bar", "/")
|
||||
result4 := strutil.AfterLast("foo/bar/baz", "/")
|
||||
result5 := strutil.AfterLast("foo/bar/foo/baz", "foo")
|
||||
|
||||
s2 := strutil.AfterLast("github.com/test/lancet", "/")
|
||||
fmt.Println(s2) //lancet
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
s3 := strutil.AfterLast("github.com/test/test/lancet", "test")
|
||||
fmt.Println(s3) // /test/lancet
|
||||
// Output:
|
||||
// foo
|
||||
//
|
||||
// bar
|
||||
// baz
|
||||
// /baz
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Before">Before</span>
|
||||
<p>Creates substring in source string before position when char first appear.</p>
|
||||
<p>Returns the substring of the source string up to the first occurrence of the specified string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -124,22 +140,26 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.Before("lancet", "")
|
||||
fmt.Println(s1) //lancet
|
||||
result1 := strutil.Before("foo", "")
|
||||
result2 := strutil.Before("foo", "foo")
|
||||
result3 := strutil.Before("foo/bar", "/")
|
||||
result4 := strutil.Before("foo/bar/baz", "/")
|
||||
|
||||
s2 := strutil.Before("github.com/test/lancet", "/")
|
||||
fmt.Println(s2) //github.com
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
s3 := strutil.Before("github.com/test/lancet", "test")
|
||||
fmt.Println(s3) // github.com/
|
||||
// Output:
|
||||
// foo
|
||||
//
|
||||
// foo
|
||||
// foo
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BeforeLast">BeforeLast</span>
|
||||
<p>Creates substring in source string before position when char first appear.</p>
|
||||
<p>Returns the substring of the source string up to the last occurrence of the specified string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -155,18 +175,24 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.BeforeLast("lancet", "")
|
||||
fmt.Println(s1) //lancet
|
||||
result1 := strutil.BeforeLast("foo", "")
|
||||
result2 := strutil.BeforeLast("foo", "foo")
|
||||
result3 := strutil.BeforeLast("foo/bar", "/")
|
||||
result4 := strutil.BeforeLast("foo/bar/baz", "/")
|
||||
|
||||
s2 := strutil.BeforeLast("github.com/test/lancet", "/")
|
||||
fmt.Println(s2) //github.com/test
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
s3 := strutil.BeforeLast("github.com/test/test/lancet", "test")
|
||||
fmt.Println(s3) //github.com/test/
|
||||
// Output:
|
||||
// foo
|
||||
//
|
||||
// foo
|
||||
// foo/bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="CamelCase">CamelCase</span>
|
||||
<p>Coverts string to camelCase string, non letters and numbers will be ignored.</p>
|
||||
|
||||
@@ -184,25 +210,22 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.CamelCase("foo_bar")
|
||||
fmt.Println(s1) //fooBar
|
||||
strings := []string{"", "foobar", "&FOO:BAR$BAZ", "$foo%", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
s2 := strutil.CamelCase("Foo-Bar")
|
||||
fmt.Println(s2) //fooBar
|
||||
|
||||
s3 := strutil.CamelCase("Foo&bar")
|
||||
fmt.Println(s3) //fooBar
|
||||
|
||||
s4 := strutil.CamelCase("foo bar")
|
||||
fmt.Println(s4) //fooBar
|
||||
|
||||
s4 := strutil.CamelCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s4) //foo11Bar
|
||||
for _, v := range strings {
|
||||
s := strutil.CamelCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
// Output:
|
||||
//
|
||||
// foobar
|
||||
// fooBarBaz
|
||||
// foo
|
||||
// foo11Bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="KebabCase">KebabCase</span>
|
||||
<p>KebabCase covert string to kebab-case, non letters and numbers will be ignored.</p>
|
||||
|
||||
@@ -220,29 +243,29 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.KebabCase("Foo Bar-")
|
||||
fmt.Println(s1) //foo-bar
|
||||
strings := []string{"", "foo-bar", "Foo Bar-", "FOOBAR", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
s2 := strutil.KebabCase("foo_Bar")
|
||||
fmt.Println(s2) //foo-bar
|
||||
for _, v := range strings {
|
||||
s := strutil.KebabCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
s3 := strutil.KebabCase("fooBar")
|
||||
fmt.Println(s3) //foo-bar
|
||||
|
||||
s4 := strutil.KebabCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //foo-bar
|
||||
// Output:
|
||||
//
|
||||
// foo-bar
|
||||
// foo-bar
|
||||
// foobar
|
||||
// foo-1-1-bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="UpperKebabCase">UpperKebabCase</span>
|
||||
<p>UpperKebabCase covert string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func KebabCase(s string) string
|
||||
func UpperKebabCase(s string) string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -253,23 +276,22 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.UpperKebabCase("Foo Bar-")
|
||||
fmt.Println(s1) //FOO-BAR
|
||||
strings := []string{"", "foo-bar", "Foo Bar-", "FooBAR", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
s2 := strutil.UpperKebabCase("foo_Bar")
|
||||
fmt.Println(s2) //FOO-BAR
|
||||
for _, v := range strings {
|
||||
s := strutil.UpperKebabCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
s3 := strutil.UpperKebabCase("fooBar")
|
||||
fmt.Println(s3) //FOO-BAR
|
||||
|
||||
s4 := strutil.UpperKebabCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //FOO-BAR
|
||||
// Output:
|
||||
//
|
||||
// FOO-BAR
|
||||
// FOO-BAR
|
||||
// FOO-BAR
|
||||
// FOO-1-1-BAR
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Capitalize">Capitalize</span>
|
||||
<p>Convert the first character of a string to upper case.</p>
|
||||
|
||||
@@ -287,19 +309,22 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.Capitalize("foo")
|
||||
fmt.Println(s1) //foo
|
||||
strings := []string{"", "Foo", "_foo", "fooBar", "foo-bar"}
|
||||
|
||||
s2 := strutil.Capitalize("Foo")
|
||||
fmt.Println(s2) //foo
|
||||
for _, v := range strings {
|
||||
s := strutil.Capitalize(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
s3 := strutil.Capitalize("FOo"
|
||||
fmt.Println(s3) //fOo
|
||||
// Output:
|
||||
//
|
||||
// Foo
|
||||
// _foo
|
||||
// Foobar
|
||||
// Foo-bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="IsString">IsString</span>
|
||||
<p>Check if the value's data type is string.</p>
|
||||
|
||||
@@ -317,51 +342,27 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(strutil.IsString("lancet")) //true
|
||||
fmt.Println(strutil.IsString("")) //true
|
||||
result1 := strutil.IsString("")
|
||||
result2 := strutil.IsString("a")
|
||||
result3 := strutil.IsString(1)
|
||||
result4 := strutil.IsString(true)
|
||||
result5 := strutil.IsString([]string{"a"})
|
||||
|
||||
fmt.Println(strutil.IsString(1)) //false
|
||||
fmt.Println(strutil.IsString("")) //false
|
||||
fmt.Println(strutil.IsString([]string{})) //false
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="KebabCase">KebabCase</span>
|
||||
<p>Covert string to kebab-case.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func KebabCase(s string) string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.KebabCase("Foo Bar-")
|
||||
fmt.Println(s1) //foo-bar
|
||||
|
||||
s2 := strutil.KebabCase("foo_Bar")
|
||||
fmt.Println(s2) //foo-bar
|
||||
|
||||
s3 := strutil.KebabCase("fooBar")
|
||||
fmt.Println(s3) //foo-bar
|
||||
|
||||
s4 := strutil.KebabCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //f-o-o-b-a-r
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LowerFirst">LowerFirst</span>
|
||||
<p>Convert the first character of string to lower case.</p>
|
||||
|
||||
@@ -379,23 +380,21 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.LowerFirst("foo")
|
||||
fmt.Println(s1) //foo
|
||||
strings := []string{"", "bar", "BAr", "Bar大"}
|
||||
|
||||
s2 := strutil.LowerFirst("BAR")
|
||||
fmt.Println(s2) //bAR
|
||||
for _, v := range strings {
|
||||
s := strutil.LowerFirst(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
s3 := strutil.LowerFirst("FOo")
|
||||
fmt.Println(s3) //fOo
|
||||
|
||||
s4 := strutil.LowerFirst("fOo大")
|
||||
fmt.Println(s4) //fOo大
|
||||
// Output:
|
||||
//
|
||||
// bar
|
||||
// bAr
|
||||
// bar大
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="UpperFirst">UpperFirst</span>
|
||||
<p>Convert the first character of string to upper case.</p>
|
||||
|
||||
@@ -413,23 +412,21 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.UpperFirst("foo")
|
||||
fmt.Println(s1) //Foo
|
||||
strings := []string{"", "bar", "BAr", "bar大"}
|
||||
|
||||
s2 := strutil.UpperFirst("bAR")
|
||||
fmt.Println(s2) //BAR
|
||||
for _, v := range strings {
|
||||
s := strutil.UpperFirst(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
s3 := strutil.UpperFirst("FOo")
|
||||
fmt.Println(s3) //FOo
|
||||
|
||||
s4 := strutil.UpperFirst("fOo大")
|
||||
fmt.Println(s4) //FOo大
|
||||
// Output:
|
||||
//
|
||||
// Bar
|
||||
// BAr
|
||||
// Bar大
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="PadEnd">PadEnd</span>
|
||||
<p>Pads string on the right side if it's shorter than size.</p>
|
||||
|
||||
@@ -447,23 +444,33 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.PadEnd("a", 1, "b")
|
||||
fmt.Println(s1) //a
|
||||
result1 := strutil.PadEnd("foo", 1, "bar")
|
||||
result2 := strutil.PadEnd("foo", 2, "bar")
|
||||
result3 := strutil.PadEnd("foo", 3, "bar")
|
||||
result4 := strutil.PadEnd("foo", 4, "bar")
|
||||
result5 := strutil.PadEnd("foo", 5, "bar")
|
||||
result6 := strutil.PadEnd("foo", 6, "bar")
|
||||
result7 := strutil.PadEnd("foo", 7, "bar")
|
||||
|
||||
s2 := strutil.PadEnd("a", 2, "b")
|
||||
fmt.Println(s2) //ab
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
s3 := strutil.PadEnd("abcd", 6, "mno")
|
||||
fmt.Println(s3) //abcdmn
|
||||
|
||||
s4 := strutil.PadEnd("abc", 6, "ab")
|
||||
fmt.Println(s4) //abcaba
|
||||
// Output:
|
||||
// foo
|
||||
// foo
|
||||
// foo
|
||||
// foob
|
||||
// fooba
|
||||
// foobar
|
||||
// foobarb
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="PadStart">PadStart</span>
|
||||
<p>Pads string on the left side if it's shorter than size.</p>
|
||||
|
||||
@@ -481,23 +488,33 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.PadStart("a", 1, "b")
|
||||
fmt.Println(s1) //a
|
||||
result1 := strutil.PadStart("foo", 1, "bar")
|
||||
result2 := strutil.PadStart("foo", 2, "bar")
|
||||
result3 := strutil.PadStart("foo", 3, "bar")
|
||||
result4 := strutil.PadStart("foo", 4, "bar")
|
||||
result5 := strutil.PadStart("foo", 5, "bar")
|
||||
result6 := strutil.PadStart("foo", 6, "bar")
|
||||
result7 := strutil.PadStart("foo", 7, "bar")
|
||||
|
||||
s2 := strutil.PadStart("a", 2, "b")
|
||||
fmt.Println(s2) //ba
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
s3 := strutil.PadStart("abcd", 6, "mno")
|
||||
fmt.Println(s3) //mnabcd
|
||||
|
||||
s4 := strutil.PadStart("abc", 6, "ab")
|
||||
fmt.Println(s4) //abaabc
|
||||
// Output:
|
||||
// foo
|
||||
// foo
|
||||
// foo
|
||||
// bfoo
|
||||
// bafoo
|
||||
// barfoo
|
||||
// barbfoo
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Reverse">Reverse</span>
|
||||
<p>Return string whose char order is reversed to the given string.</p>
|
||||
|
||||
@@ -515,16 +532,18 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.ReverseStr("abc")
|
||||
fmt.Println(s1) //cba
|
||||
s := "foo"
|
||||
rs := strutil.Reverse(s)
|
||||
|
||||
s2 := strutil.ReverseStr("12345")
|
||||
fmt.Println(s2) //54321
|
||||
fmt.Println(s)
|
||||
fmt.Println(rs)
|
||||
|
||||
// Output:
|
||||
// foo
|
||||
// oof
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="SnakeCase">SnakeCase</span>
|
||||
<p>Coverts string to snake_case, non letters and numbers will be ignored.</p>
|
||||
|
||||
@@ -542,24 +561,22 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.SnakeCase("Foo Bar-")
|
||||
fmt.Println(s1) //foo_bar
|
||||
strings := []string{"", "foo-bar", "Foo Bar-", "FOOBAR", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
s2 := strutil.SnakeCase("foo_Bar")
|
||||
fmt.Println(s2) //foo_bar
|
||||
for _, v := range strings {
|
||||
s := strutil.SnakeCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
s3 := strutil.SnakeCase("fooBar")
|
||||
fmt.Println(s3) //foo_bar
|
||||
|
||||
s4 := strutil.SnakeCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //foo_bar
|
||||
|
||||
s5 := strutil.SnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s5) //foo_1_1_bar
|
||||
// Output:
|
||||
//
|
||||
// foo_bar
|
||||
// foo_bar
|
||||
// foobar
|
||||
// foo_1_1_bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="UpperSnakeCase">UpperSnakeCase</span>
|
||||
<p>Coverts string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
|
||||
|
||||
@@ -577,24 +594,22 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.UpperSnakeCase("Foo Bar-")
|
||||
fmt.Println(s1) //FOO_BAR
|
||||
strings := []string{"", "foo-bar", "Foo Bar-", "FooBAR", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
s2 := strutil.UpperSnakeCase("foo_Bar")
|
||||
fmt.Println(s2) //FOO_BAR
|
||||
for _, v := range strings {
|
||||
s := strutil.UpperSnakeCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
s3 := strutil.UpperSnakeCase("fooBar")
|
||||
fmt.Println(s3) //FOO_BAR
|
||||
|
||||
s4 := strutil.UpperSnakeCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //FOO_BAR
|
||||
|
||||
s5 := strutil.UpperSnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s5) //FOO_1_1_BAR
|
||||
// Output:
|
||||
//
|
||||
// FOO_BAR
|
||||
// FOO_BAR
|
||||
// FOO_BAR
|
||||
// FOO_1_1_BAR
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="SplitEx">SplitEx</span>
|
||||
<p>Split a given string whether the result contains empty string.</p>
|
||||
|
||||
@@ -612,28 +627,71 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
arr1 := strutil.SplitEx(" a b c ", "", true)
|
||||
fmt.Println(arr1) //[]string{}
|
||||
result1 := strutil.SplitEx(" a b c ", "", true)
|
||||
|
||||
arr2 := strutil.SplitEx(" a b c ", " ", false)
|
||||
fmt.Println(arr2) //[]string{"", "a", "b", "c", ""}
|
||||
result2 := strutil.SplitEx(" a b c ", " ", false)
|
||||
result3 := strutil.SplitEx(" a b c ", " ", true)
|
||||
|
||||
arr3 := strutil.SplitEx(" a b c ", " ", true)
|
||||
fmt.Println(arr3) //[]string{"a", "b", "c"}
|
||||
result4 := strutil.SplitEx("a = b = c = ", " = ", false)
|
||||
result5 := strutil.SplitEx("a = b = c = ", " = ", true)
|
||||
|
||||
arr4 := strutil.SplitEx(" a = b = c = ", " = ", false)
|
||||
fmt.Println(arr4) //[]string{" a", "b", "c", ""}
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
arr5 := strutil.SplitEx(" a = b = c = ", " = ", true)
|
||||
fmt.Println(arr5) //[]string{" a", "b", "c"}
|
||||
// Output:
|
||||
// []
|
||||
// [ a b c ]
|
||||
// [a b c]
|
||||
// [a b c ]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Substring">Substring</span>
|
||||
<p>Returns a substring of the specified length starting at the specified offset position.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func Substring(s string, offset int, length uint) string
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.Substring("abcde", 1, 3)
|
||||
result2 := strutil.Substring("abcde", 1, 5)
|
||||
result3 := strutil.Substring("abcde", -1, 3)
|
||||
result4 := strutil.Substring("abcde", -2, 2)
|
||||
result5 := strutil.Substring("abcde", -2, 3)
|
||||
result6 := strutil.Substring("你好,欢迎你", 0, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// bcd
|
||||
// bcde
|
||||
// e
|
||||
// de
|
||||
// de
|
||||
// 你好
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Wrap">Wrap</span>
|
||||
<p>Wrap a string with another string.</p>
|
||||
<p>Wrap a string with given string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -649,28 +707,27 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.Wrap("ab", "")
|
||||
fmt.Println(s1) //ab
|
||||
result1 := strutil.Wrap("foo", "")
|
||||
result2 := strutil.Wrap("foo", "*")
|
||||
result3 := strutil.Wrap("'foo'", "'")
|
||||
result4 := strutil.Wrap("", "*")
|
||||
|
||||
s2 := strutil.Wrap("", "*")
|
||||
fmt.Println(s2) //""
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
s3 := strutil.Wrap("ab", "*")
|
||||
fmt.Println(s3) //*ab*
|
||||
|
||||
s4 := strutil.Wrap("ab", "\"")
|
||||
fmt.Println(s4) //\"ab\"
|
||||
|
||||
s5 := strutil.Wrap("ab", "'")
|
||||
fmt.Println(s5) //'ab'
|
||||
// Output:
|
||||
// foo
|
||||
// *foo*
|
||||
// ''foo''
|
||||
//
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Wrap">Wrap</span>
|
||||
<p>Unwrap a given string from anther string. will change str value.</p>
|
||||
<p>Unwrap a given string from anther string. will change source string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -686,20 +743,24 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.Unwrap("ab", "")
|
||||
fmt.Println(s1) //ab
|
||||
result1 := strutil.Unwrap("foo", "")
|
||||
result2 := strutil.Unwrap("*foo*", "*")
|
||||
result3 := strutil.Unwrap("*foo", "*")
|
||||
result4 := strutil.Unwrap("foo*", "*")
|
||||
result5 := strutil.Unwrap("**foo**", "*")
|
||||
|
||||
s2 := strutil.Unwrap("ab", "*")
|
||||
fmt.Println(s2) //ab
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
s3 := strutil.Unwrap("**ab**", "*")
|
||||
fmt.Println(s3) //*ab*
|
||||
|
||||
s4 := strutil.Unwrap("*ab", "*")
|
||||
fmt.Println(s4) //*ab
|
||||
|
||||
s5 := strutil.Unwrap("***", "**")
|
||||
fmt.Println(s5) //***
|
||||
// Output:
|
||||
// foo
|
||||
// foo
|
||||
// *foo
|
||||
// foo*
|
||||
// *foo*
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
- [SnakeCase](#SnakeCase)
|
||||
- [UpperSnakeCase](#UpperSnakeCase)
|
||||
- [SplitEx](#SplitEx)
|
||||
- [Substring](#Substring)
|
||||
- [Wrap](#Wrap)
|
||||
- [Unwrap](#Unwrap)
|
||||
|
||||
@@ -48,14 +49,14 @@ import (
|
||||
|
||||
|
||||
### <span id="After">After</span>
|
||||
<p>截取源字符串中char首次出现时的位置之后的子字符串</p>
|
||||
<p>返回源字符串中特定字符串首次出现时的位置之后的子字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func After(s, char string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -64,28 +65,36 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.After("lancet", "")
|
||||
fmt.Println(s1) //lancet
|
||||
result1 := strutil.After("foo", "")
|
||||
result2 := strutil.After("foo", "foo")
|
||||
result3 := strutil.After("foo/bar", "foo")
|
||||
result4 := strutil.After("foo/bar", "/")
|
||||
result5 := strutil.After("foo/bar/baz", "/")
|
||||
|
||||
s2 := strutil.After("github.com/test/lancet", "/")
|
||||
fmt.Println(s2) //test/lancet
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
s3 := strutil.After("github.com/test/lancet", "test")
|
||||
fmt.Println(s3) // /lancet
|
||||
// Output:
|
||||
// foo
|
||||
//
|
||||
// /bar
|
||||
// bar
|
||||
// bar/baz
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="AfterLast">AfterLast</span>
|
||||
<p>截取源字符串中char最后一次出现时的位置之后的子字符串</p>
|
||||
<p>返回源字符串中指定字符串最后一次出现时的位置之后的子字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func AfterLast(s, char string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -94,29 +103,36 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.AfterLast("lancet", "")
|
||||
fmt.Println(s1) //lancet
|
||||
result1 := strutil.AfterLast("foo", "")
|
||||
result2 := strutil.AfterLast("foo", "foo")
|
||||
result3 := strutil.AfterLast("foo/bar", "/")
|
||||
result4 := strutil.AfterLast("foo/bar/baz", "/")
|
||||
result5 := strutil.AfterLast("foo/bar/foo/baz", "foo")
|
||||
|
||||
s2 := strutil.AfterLast("github.com/test/lancet", "/")
|
||||
fmt.Println(s2) //lancet
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
s3 := strutil.AfterLast("github.com/test/test/lancet", "test")
|
||||
fmt.Println(s3) // /lancet
|
||||
// Output:
|
||||
// foo
|
||||
//
|
||||
// bar
|
||||
// baz
|
||||
// /baz
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Before">Before</span>
|
||||
<p>截取源字符串中char首次出现时的位置之前的子字符串</p>
|
||||
<p>返回源字符串中指定字符串第一次出现时的位置之前的子字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Before(s, char string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -125,29 +141,33 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.Before("lancet", "")
|
||||
fmt.Println(s1) //lancet
|
||||
result1 := strutil.Before("foo", "")
|
||||
result2 := strutil.Before("foo", "foo")
|
||||
result3 := strutil.Before("foo/bar", "/")
|
||||
result4 := strutil.Before("foo/bar/baz", "/")
|
||||
|
||||
s2 := strutil.Before("github.com/test/lancet", "/")
|
||||
fmt.Println(s2) //github.com
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
s3 := strutil.Before("github.com/test/lancet", "test")
|
||||
fmt.Println(s3) // github.com/
|
||||
// Output:
|
||||
// foo
|
||||
//
|
||||
// foo
|
||||
// foo
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="BeforeLast">BeforeLast</span>
|
||||
<p>截取源字符串中char最后一次出现时的位置之前的子字符串</p>
|
||||
<p>返回源字符串中指定字符串最后一次出现时的位置之前的子字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func BeforeLast(s, char string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -156,29 +176,33 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.BeforeLast("lancet", "")
|
||||
fmt.Println(s1) //lancet
|
||||
result1 := strutil.BeforeLast("foo", "")
|
||||
result2 := strutil.BeforeLast("foo", "foo")
|
||||
result3 := strutil.BeforeLast("foo/bar", "/")
|
||||
result4 := strutil.BeforeLast("foo/bar/baz", "/")
|
||||
|
||||
s2 := strutil.BeforeLast("github.com/test/lancet", "/")
|
||||
fmt.Println(s2) //github.com/test
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
s3 := strutil.BeforeLast("github.com/test/test/lancet", "test")
|
||||
fmt.Println(s3) //github.com/test/
|
||||
// Output:
|
||||
// foo
|
||||
//
|
||||
// foo
|
||||
// foo/bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="CamelCase">CamelCase</span>
|
||||
<p>将字符串转换为驼峰式字符串, 非字母和数字会被忽略</p>
|
||||
<p>将字符串转换为驼峰式字符串, 非字母和数字会被忽略。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func CamelCase(s string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -187,35 +211,97 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.CamelCase("foo_bar")
|
||||
fmt.Println(s1) //fooBar
|
||||
strings := []string{"", "foobar", "&FOO:BAR$BAZ", "$foo%", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
s2 := strutil.CamelCase("Foo-Bar")
|
||||
fmt.Println(s2) //fooBar
|
||||
for _, v := range strings {
|
||||
s := strutil.CamelCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
s3 := strutil.CamelCase("Foo&bar")
|
||||
fmt.Println(s3) //fooBar
|
||||
|
||||
s4 := strutil.CamelCase("foo bar")
|
||||
fmt.Println(s4) //fooBar
|
||||
|
||||
s4 := strutil.CamelCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s4) //foo11Bar
|
||||
// Output:
|
||||
//
|
||||
// foobar
|
||||
// fooBarBaz
|
||||
// foo
|
||||
// foo11Bar
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="KebabCase">KebabCase</span>
|
||||
<p>将字符串转换为kebab-case, 非字母和数字会被忽略。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func KebabCase(s string) string
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
strings := []string{"", "foo-bar", "Foo Bar-", "FOOBAR", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
for _, v := range strings {
|
||||
s := strutil.KebabCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
// Output:
|
||||
//
|
||||
// foo-bar
|
||||
// foo-bar
|
||||
// foobar
|
||||
// foo-1-1-bar
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="UpperKebabCase">UpperKebabCase</span>
|
||||
<p>将字符串转换为大写KEBAB-CASE, 非字母和数字会被忽略。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func UpperKebabCase(s string) string
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
strings := []string{"", "foo-bar", "Foo Bar-", "FooBAR", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
for _, v := range strings {
|
||||
s := strutil.UpperKebabCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
// Output:
|
||||
//
|
||||
// FOO-BAR
|
||||
// FOO-BAR
|
||||
// FOO-BAR
|
||||
// FOO-1-1-BAR
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Capitalize">Capitalize</span>
|
||||
<p>将字符串的第一个字符转换为大写</p>
|
||||
<p>将字符串的第一个字符转换为大写。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Capitalize(s string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -224,28 +310,31 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.Capitalize("foo")
|
||||
fmt.Println(s1) //foo
|
||||
strings := []string{"", "Foo", "_foo", "fooBar", "foo-bar"}
|
||||
|
||||
s2 := strutil.Capitalize("Foo")
|
||||
fmt.Println(s2) //foo
|
||||
for _, v := range strings {
|
||||
s := strutil.Capitalize(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
s3 := strutil.Capitalize("FOo"
|
||||
fmt.Println(s3) //fOo
|
||||
// Output:
|
||||
//
|
||||
// Foo
|
||||
// _foo
|
||||
// Foobar
|
||||
// Foo-bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="IsString">IsString</span>
|
||||
<p>检查值的数据类型是否为字符串</p>
|
||||
<p>判断传入参数的数据类型是否为字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func IsString(v any) bool
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -254,93 +343,36 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(strutil.IsString("lancet")) //true
|
||||
fmt.Println(strutil.IsString("")) //true
|
||||
result1 := strutil.IsString("")
|
||||
result2 := strutil.IsString("a")
|
||||
result3 := strutil.IsString(1)
|
||||
result4 := strutil.IsString(true)
|
||||
result5 := strutil.IsString([]string{"a"})
|
||||
|
||||
fmt.Println(strutil.IsString(1)) //false
|
||||
fmt.Println(strutil.IsString("")) //false
|
||||
fmt.Println(strutil.IsString([]string{})) //false
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="KebabCase">KebabCase</span>
|
||||
<p>将字符串转换为kebab-case, 非字母和数字会被忽略</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func KebabCase(s string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.KebabCase("Foo Bar-")
|
||||
fmt.Println(s1) //foo-bar
|
||||
|
||||
s2 := strutil.KebabCase("foo_Bar")
|
||||
fmt.Println(s2) //foo-bar
|
||||
|
||||
s3 := strutil.KebabCase("fooBar")
|
||||
fmt.Println(s3) //foo-bar
|
||||
|
||||
s4 := strutil.KebabCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //foo-bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="UpperKebabCase">UpperKebabCase</span>
|
||||
<p>将字符串转换为大写KEBAB-CASE, 非字母和数字会被忽略</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func KebabCase(s string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.UpperKebabCase("Foo Bar-")
|
||||
fmt.Println(s1) //FOO-BAR
|
||||
|
||||
s2 := strutil.UpperKebabCase("foo_Bar")
|
||||
fmt.Println(s2) //FOO-BAR
|
||||
|
||||
s3 := strutil.UpperKebabCase("fooBar")
|
||||
fmt.Println(s3) //FOO-BAR
|
||||
|
||||
s4 := strutil.UpperKebabCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //FOO-BAR
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="LowerFirst">LowerFirst</span>
|
||||
<p>将字符串的第一个字符转换为小写</p>
|
||||
<p>将字符串的第一个字符转换为小写。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func LowerFirst(s string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -349,32 +381,30 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.LowerFirst("foo")
|
||||
fmt.Println(s1) //foo
|
||||
strings := []string{"", "bar", "BAr", "Bar大"}
|
||||
|
||||
s2 := strutil.LowerFirst("BAR")
|
||||
fmt.Println(s2) //bAR
|
||||
for _, v := range strings {
|
||||
s := strutil.LowerFirst(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
s3 := strutil.LowerFirst("FOo")
|
||||
fmt.Println(s3) //fOo
|
||||
|
||||
s4 := strutil.LowerFirst("fOo大")
|
||||
fmt.Println(s4) //fOo大
|
||||
// Output:
|
||||
//
|
||||
// bar
|
||||
// bAr
|
||||
// bar大
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="UpperFirst">UpperFirst</span>
|
||||
<p>将字符串的第一个字符转换为大写</p>
|
||||
<p>将字符串的第一个字符转换为大写形式。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func UpperFirst(s string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -383,32 +413,30 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.UpperFirst("foo")
|
||||
fmt.Println(s1) //Foo
|
||||
strings := []string{"", "bar", "BAr", "bar大"}
|
||||
|
||||
s2 := strutil.UpperFirst("bAR")
|
||||
fmt.Println(s2) //BAR
|
||||
for _, v := range strings {
|
||||
s := strutil.UpperFirst(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
s3 := strutil.UpperFirst("FOo")
|
||||
fmt.Println(s3) //FOo
|
||||
|
||||
s4 := strutil.UpperFirst("fOo大")
|
||||
fmt.Println(s4) //FOo大
|
||||
// Output:
|
||||
//
|
||||
// Bar
|
||||
// BAr
|
||||
// Bar大
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="PadEnd">PadEnd</span>
|
||||
<p>如果字符串长度短于size,则在右侧填充字符串</p>
|
||||
<p>如果字符串长度短于size,则在右侧填充字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func PadEnd(source string, size int, padStr string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -417,32 +445,42 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.PadEnd("a", 1, "b")
|
||||
fmt.Println(s1) //a
|
||||
result1 := strutil.PadEnd("foo", 1, "bar")
|
||||
result2 := strutil.PadEnd("foo", 2, "bar")
|
||||
result3 := strutil.PadEnd("foo", 3, "bar")
|
||||
result4 := strutil.PadEnd("foo", 4, "bar")
|
||||
result5 := strutil.PadEnd("foo", 5, "bar")
|
||||
result6 := strutil.PadEnd("foo", 6, "bar")
|
||||
result7 := strutil.PadEnd("foo", 7, "bar")
|
||||
|
||||
s2 := strutil.PadEnd("a", 2, "b")
|
||||
fmt.Println(s2) //ab
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
s3 := strutil.PadEnd("abcd", 6, "mno")
|
||||
fmt.Println(s3) //abcdmn
|
||||
|
||||
s4 := strutil.PadEnd("abc", 6, "ab")
|
||||
fmt.Println(s4) //abcaba
|
||||
// Output:
|
||||
// foo
|
||||
// foo
|
||||
// foo
|
||||
// foob
|
||||
// fooba
|
||||
// foobar
|
||||
// foobarb
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="PadStart">PadStart</span>
|
||||
<p>如果字符串长度短于size,则在左侧填充字符串</p>
|
||||
<p>如果字符串长度短于size,则在左侧填充字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func PadStart(source string, size int, padStr string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -451,32 +489,42 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.PadStart("a", 1, "b")
|
||||
fmt.Println(s1) //a
|
||||
result1 := strutil.PadStart("foo", 1, "bar")
|
||||
result2 := strutil.PadStart("foo", 2, "bar")
|
||||
result3 := strutil.PadStart("foo", 3, "bar")
|
||||
result4 := strutil.PadStart("foo", 4, "bar")
|
||||
result5 := strutil.PadStart("foo", 5, "bar")
|
||||
result6 := strutil.PadStart("foo", 6, "bar")
|
||||
result7 := strutil.PadStart("foo", 7, "bar")
|
||||
|
||||
s2 := strutil.PadStart("a", 2, "b")
|
||||
fmt.Println(s2) //ba
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
|
||||
s3 := strutil.PadStart("abcd", 6, "mno")
|
||||
fmt.Println(s3) //mnabcd
|
||||
|
||||
s4 := strutil.PadStart("abc", 6, "ab")
|
||||
fmt.Println(s4) //abaabc
|
||||
// Output:
|
||||
// foo
|
||||
// foo
|
||||
// foo
|
||||
// bfoo
|
||||
// bafoo
|
||||
// barfoo
|
||||
// barbfoo
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Reverse">Reverse</span>
|
||||
<p>返回字符顺序与给定字符串相反的字符串</p>
|
||||
<p>返回字符顺序与给定字符串相反的字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Reverse(s string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -485,25 +533,27 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.ReverseStr("abc")
|
||||
fmt.Println(s1) //cba
|
||||
s := "foo"
|
||||
rs := strutil.Reverse(s)
|
||||
|
||||
s2 := strutil.ReverseStr("12345")
|
||||
fmt.Println(s2) //54321
|
||||
fmt.Println(s)
|
||||
fmt.Println(rs)
|
||||
|
||||
// Output:
|
||||
// foo
|
||||
// oof
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="SnakeCase">SnakeCase</span>
|
||||
<p>将字符串转换为snake_case形式, 非字母和数字会被忽略</p>
|
||||
<p>将字符串转换为snake_case形式, 非字母和数字会被忽略。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func SnakeCase(s string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -512,33 +562,31 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.SnakeCase("Foo Bar-")
|
||||
fmt.Println(s1) //foo_bar
|
||||
strings := []string{"", "foo-bar", "Foo Bar-", "FOOBAR", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
s2 := strutil.SnakeCase("foo_Bar")
|
||||
fmt.Println(s2) //foo_bar
|
||||
for _, v := range strings {
|
||||
s := strutil.SnakeCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
s3 := strutil.SnakeCase("fooBar")
|
||||
fmt.Println(s3) //foo_bar
|
||||
|
||||
s4 := strutil.SnakeCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //foo_bar
|
||||
|
||||
s5 := strutil.SnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s5) //foo_1_1_bar
|
||||
// Output:
|
||||
//
|
||||
// foo_bar
|
||||
// foo_bar
|
||||
// foobar
|
||||
// foo_1_1_bar
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="UpperSnakeCase">UpperSnakeCase</span>
|
||||
<p>将字符串转换为大写SNAKE_CASE形式, 非字母和数字会被忽略</p>
|
||||
<p>将字符串转换为大写SNAKE_CASE形式, 非字母和数字会被忽略。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func SnakeCase(s string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -547,34 +595,31 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.UpperSnakeCase("Foo Bar-")
|
||||
fmt.Println(s1) //FOO_BAR
|
||||
strings := []string{"", "foo-bar", "Foo Bar-", "FooBAR", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
s2 := strutil.UpperSnakeCase("foo_Bar")
|
||||
fmt.Println(s2) //FOO_BAR
|
||||
for _, v := range strings {
|
||||
s := strutil.UpperSnakeCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
s3 := strutil.UpperSnakeCase("fooBar")
|
||||
fmt.Println(s3) //FOO_BAR
|
||||
|
||||
s4 := strutil.UpperSnakeCase("__FOO_BAR__")
|
||||
fmt.Println(s4) //FOO_BAR
|
||||
|
||||
s5 := strutil.UpperSnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||
fmt.Println(s5) //FOO_1_1_BAR
|
||||
// Output:
|
||||
//
|
||||
// FOO_BAR
|
||||
// FOO_BAR
|
||||
// FOO_BAR
|
||||
// FOO_1_1_BAR
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="SplitEx">SplitEx</span>
|
||||
<p>分割字符串为切片,removeEmptyString参数指定是否去除空字符串</p>
|
||||
<p>分割字符串为切片,removeEmptyString参数指定是否去除空字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func SplitEx(s, sep string, removeEmptyString bool) []string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -583,34 +628,78 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
arr1 := strutil.SplitEx(" a b c ", "", true)
|
||||
fmt.Println(arr1) //[]string{}
|
||||
result1 := strutil.SplitEx(" a b c ", "", true)
|
||||
|
||||
arr2 := strutil.SplitEx(" a b c ", " ", false)
|
||||
fmt.Println(arr2) //[]string{"", "a", "b", "c", ""}
|
||||
result2 := strutil.SplitEx(" a b c ", " ", false)
|
||||
result3 := strutil.SplitEx(" a b c ", " ", true)
|
||||
|
||||
arr3 := strutil.SplitEx(" a b c ", " ", true)
|
||||
fmt.Println(arr3) //[]string{"a", "b", "c"}
|
||||
result4 := strutil.SplitEx("a = b = c = ", " = ", false)
|
||||
result5 := strutil.SplitEx("a = b = c = ", " = ", true)
|
||||
|
||||
arr4 := strutil.SplitEx(" a = b = c = ", " = ", false)
|
||||
fmt.Println(arr4) //[]string{" a", "b", "c", ""}
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
arr5 := strutil.SplitEx(" a = b = c = ", " = ", true)
|
||||
fmt.Println(arr5) //[]string{" a", "b", "c"}
|
||||
// Output:
|
||||
// []
|
||||
// [ a b c ]
|
||||
// [a b c]
|
||||
// [a b c ]
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Substring">Substring</span>
|
||||
<p>根据指定的位置和长度截取字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Substring(s string, offset int, length uint) string
|
||||
```
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/v2/strutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := strutil.Substring("abcde", 1, 3)
|
||||
result2 := strutil.Substring("abcde", 1, 5)
|
||||
result3 := strutil.Substring("abcde", -1, 3)
|
||||
result4 := strutil.Substring("abcde", -2, 2)
|
||||
result5 := strutil.Substring("abcde", -2, 3)
|
||||
result6 := strutil.Substring("你好,欢迎你", 0, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
|
||||
// Output:
|
||||
// bcd
|
||||
// bcde
|
||||
// e
|
||||
// de
|
||||
// de
|
||||
// 你好
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Wrap">Wrap</span>
|
||||
<p>用另一个字符串包裹一个字符串</p>
|
||||
<p>用另一个字符串包裹一个字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Wrap(str string, wrapWith string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -619,35 +708,34 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.Wrap("ab", "")
|
||||
fmt.Println(s1) //ab
|
||||
result1 := strutil.Wrap("foo", "")
|
||||
result2 := strutil.Wrap("foo", "*")
|
||||
result3 := strutil.Wrap("'foo'", "'")
|
||||
result4 := strutil.Wrap("", "*")
|
||||
|
||||
s2 := strutil.Wrap("", "*")
|
||||
fmt.Println(s2) //""
|
||||
|
||||
s3 := strutil.Wrap("ab", "*")
|
||||
fmt.Println(s3) //*ab*
|
||||
|
||||
s4 := strutil.Wrap("ab", "\"")
|
||||
fmt.Println(s4) //\"ab\"
|
||||
|
||||
s5 := strutil.Wrap("ab", "'")
|
||||
fmt.Println(s5) //'ab'
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// foo
|
||||
// *foo*
|
||||
// ''foo''
|
||||
//
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="Unwrap">Unwrap</span>
|
||||
<p>用另一个字符串解开包裹一个字符串</p>
|
||||
### <span id="Wrap">Wrap</span>
|
||||
<p>用另一个字符串解开包裹一个字符串。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func Unwrap(str string, wrapToken string) string
|
||||
```
|
||||
<b>例子:</b>
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
import (
|
||||
@@ -656,28 +744,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
s1 := strutil.Unwrap("ab", "")
|
||||
fmt.Println(s1) //ab
|
||||
result1 := strutil.Unwrap("foo", "")
|
||||
result2 := strutil.Unwrap("*foo*", "*")
|
||||
result3 := strutil.Unwrap("*foo", "*")
|
||||
result4 := strutil.Unwrap("foo*", "*")
|
||||
result5 := strutil.Unwrap("**foo**", "*")
|
||||
|
||||
s2 := strutil.Unwrap("ab", "*")
|
||||
fmt.Println(s2) //ab
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
s3 := strutil.Unwrap("**ab**", "*")
|
||||
fmt.Println(s3) //*ab*
|
||||
|
||||
s4 := strutil.Unwrap("*ab", "*")
|
||||
fmt.Println(s4) //*ab
|
||||
|
||||
s5 := strutil.Unwrap("***", "**")
|
||||
fmt.Println(s5) //***
|
||||
// Output:
|
||||
// foo
|
||||
// foo
|
||||
// *foo
|
||||
// foo*
|
||||
// *foo*
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
@@ -102,7 +102,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
isOsMac := system.IsMac
|
||||
isOsMac := system.IsMac()
|
||||
fmt.Println(isOsMac)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
- [GetOsEnv](#GetOsEnv)
|
||||
- [SetOsEnv](#SetOsEnv)
|
||||
- [RemoveOsEnv](#RemoveOsEnv)
|
||||
|
||||
- [CompareOsEnv](#CompareOsEnv)
|
||||
- [ExecCommand](#ExecCommand)
|
||||
- [GetOsBits](#GetOsBits)
|
||||
@@ -103,7 +102,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
isOsMac := system.IsMac
|
||||
isOsMac := system.IsMac()
|
||||
fmt.Println(isOsMac)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -459,8 +459,6 @@ func main() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IsEmptyString">IsEmptyString</span>
|
||||
<p>验证字符串是否是空字符串</p>
|
||||
|
||||
@@ -488,7 +486,6 @@ func main() {
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IsFloatStr">IsFloatStr</span>
|
||||
<p>验证字符串是否是可以转换为浮点数</p>
|
||||
|
||||
@@ -574,8 +571,6 @@ func main() {
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IsRegexMatch">IsRegexMatch</span>
|
||||
<p>验证字符串是否可以匹配正则表达式</p>
|
||||
|
||||
@@ -601,7 +596,6 @@ func main() {
|
||||
|
||||
|
||||
|
||||
|
||||
### <span id="IsIntStr">IsIntStr</span>
|
||||
<p>验证字符串是否是可以转换为整数</p>
|
||||
|
||||
|
||||
@@ -46,12 +46,20 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := xerror.Unwrap(strconv.Atoi("42"))
|
||||
fmt.Println(result1)
|
||||
|
||||
_, err := strconv.Atoi("4o2")
|
||||
defer func() {
|
||||
v := recover()
|
||||
fmt.Println(err.Error()) // err.Error() == v.(*strconv.NumError).Error()
|
||||
result2 := reflect.DeepEqual(err.Error(), v.(*strconv.NumError).Error())
|
||||
fmt.Println(result2)
|
||||
}()
|
||||
|
||||
xerror.Unwrap(strconv.Atoi("4o2"))
|
||||
|
||||
// Output:
|
||||
// 42
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
|
||||
|
||||
### <span id="Unwrap">Unwrap</span>
|
||||
<p>如果err为nil则展开,则它返回一个有效值。 如果err不是nil则Unwrap使用err发生恐慌。</p>
|
||||
<p>检查error, 如果err为nil则展开,则它返回一个有效值,如果err不是nil则Unwrap使用err发生panic。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -46,12 +46,20 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
result1 := xerror.Unwrap(strconv.Atoi("42"))
|
||||
fmt.Println(result1)
|
||||
|
||||
_, err := strconv.Atoi("4o2")
|
||||
defer func() {
|
||||
v := recover()
|
||||
fmt.Println(err.Error()) // err.Error() == v.(*strconv.NumError).Error()
|
||||
result2 := reflect.DeepEqual(err.Error(), v.(*strconv.NumError).Error())
|
||||
fmt.Println(result2)
|
||||
}()
|
||||
|
||||
xerror.Unwrap(strconv.Atoi("4o2"))
|
||||
|
||||
// Output:
|
||||
// 42
|
||||
// true
|
||||
}
|
||||
```
|
||||
|
||||
@@ -18,7 +18,8 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IsExist checks if a file or directory exists
|
||||
// IsExist checks if a file or directory exists.
|
||||
// Play: https://go.dev/play/p/nKKXt8ZQbmh
|
||||
func IsExist(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
if err == nil {
|
||||
@@ -30,7 +31,8 @@ func IsExist(path string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// CreateFile create a file in path
|
||||
// CreateFile create a file in path.
|
||||
// Play: https://go.dev/play/p/lDt8PEsTNKI
|
||||
func CreateFile(path string) bool {
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
@@ -41,12 +43,14 @@ func CreateFile(path string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// CreateDir create directory in absolute path. param `absPath` like /a/, /a/b/
|
||||
// CreateDir create directory in absolute path. param `absPath` like /a/, /a/b/.
|
||||
// Play: https://go.dev/play/p/qUuCe1OGQnM
|
||||
func CreateDir(absPath string) error {
|
||||
return os.MkdirAll(path.Dir(absPath), os.ModePerm)
|
||||
}
|
||||
|
||||
// IsDir checks if the path is directory or not
|
||||
// IsDir checks if the path is directory or not.
|
||||
// Play: https://go.dev/play/p/WkVwEKqtOWk
|
||||
func IsDir(path string) bool {
|
||||
file, err := os.Stat(path)
|
||||
if err != nil {
|
||||
@@ -55,12 +59,14 @@ func IsDir(path string) bool {
|
||||
return file.IsDir()
|
||||
}
|
||||
|
||||
// RemoveFile remove the path file
|
||||
// RemoveFile remove the path file.
|
||||
// Play: https://go.dev/play/p/P2y0XW8a1SH
|
||||
func RemoveFile(path string) error {
|
||||
return os.Remove(path)
|
||||
}
|
||||
|
||||
// CopyFile copy src file to dest file
|
||||
// CopyFile copy src file to dest file.
|
||||
// Play: https://go.dev/play/p/Jg9AMJMLrJi
|
||||
func CopyFile(srcFilePath string, dstFilePath string) error {
|
||||
srcFile, err := os.Open(srcFilePath)
|
||||
if err != nil {
|
||||
@@ -90,7 +96,8 @@ func CopyFile(srcFilePath string, dstFilePath string) error {
|
||||
}
|
||||
}
|
||||
|
||||
//ClearFile write empty string to path file
|
||||
// ClearFile write empty string to path file.
|
||||
// Play: https://go.dev/play/p/NRZ0ZT-G94H
|
||||
func ClearFile(path string) error {
|
||||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
if err != nil {
|
||||
@@ -102,7 +109,8 @@ func ClearFile(path string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
//ReadFileToString return string of file content
|
||||
// ReadFileToString return string of file content.
|
||||
// Play: https://go.dev/play/p/cmfwp_5SQTp
|
||||
func ReadFileToString(path string) (string, error) {
|
||||
bytes, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
@@ -111,7 +119,8 @@ func ReadFileToString(path string) (string, error) {
|
||||
return string(bytes), nil
|
||||
}
|
||||
|
||||
// ReadFileByLine read file line by line
|
||||
// ReadFileByLine read file line by line.
|
||||
// Play: https://go.dev/play/p/svJP_7ZrBrD
|
||||
func ReadFileByLine(path string) ([]string, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
@@ -137,7 +146,8 @@ func ReadFileByLine(path string) ([]string, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ListFileNames return all file names in the path
|
||||
// ListFileNames return all file names in the path.
|
||||
// Play: https://go.dev/play/p/Tjd7Y07rejl
|
||||
func ListFileNames(path string) ([]string, error) {
|
||||
if !IsExist(path) {
|
||||
return []string{}, nil
|
||||
@@ -163,7 +173,8 @@ func ListFileNames(path string) ([]string, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Zip create zip file, fpath could be a single file or a directory
|
||||
// Zip create zip file, fpath could be a single file or a directory.
|
||||
// Play: https://go.dev/play/p/j-3sWBp8ik_P
|
||||
func Zip(fpath string, destPath string) error {
|
||||
zipFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
@@ -218,7 +229,8 @@ func Zip(fpath string, destPath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnZip unzip the file and save it to destPath
|
||||
// UnZip unzip the file and save it to destPath.
|
||||
// Play: https://go.dev/play/p/g0w34kS7B8m
|
||||
func UnZip(zipFile string, destPath string) error {
|
||||
|
||||
zipReader, err := zip.OpenReader(zipFile)
|
||||
@@ -277,7 +289,8 @@ func safeFilepathJoin(path1, path2 string) (string, error) {
|
||||
return filepath.Join(path1, filepath.Join("/", relPath)), nil
|
||||
}
|
||||
|
||||
// IsLink checks if a file is symbol link or not
|
||||
// IsLink checks if a file is symbol link or not.
|
||||
// Play: https://go.dev/play/p/TL-b-Kzvf44
|
||||
func IsLink(path string) bool {
|
||||
fi, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
@@ -286,7 +299,8 @@ func IsLink(path string) bool {
|
||||
return fi.Mode()&os.ModeSymlink != 0
|
||||
}
|
||||
|
||||
// FileMode return file's mode and permission
|
||||
// FileMode return file's mode and permission.
|
||||
// Play: https://go.dev/play/p/2l2hI42fA3p
|
||||
func FileMode(path string) (fs.FileMode, error) {
|
||||
fi, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
@@ -296,7 +310,8 @@ func FileMode(path string) (fs.FileMode, error) {
|
||||
}
|
||||
|
||||
// MiMeType return file mime type
|
||||
// param `file` should be string(file path) or *os.File
|
||||
// param `file` should be string(file path) or *os.File.
|
||||
// Play: https://go.dev/play/p/bd5sevSUZNu
|
||||
func MiMeType(file any) string {
|
||||
var mediatype string
|
||||
|
||||
|
||||
225
fileutil/file_example_test.go
Normal file
225
fileutil/file_example_test.go
Normal file
@@ -0,0 +1,225 @@
|
||||
package fileutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func ExampleIsExist() {
|
||||
|
||||
result1 := IsExist("./")
|
||||
result2 := IsExist("./xxx.go")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleCreateFile() {
|
||||
fname := "./a.txt"
|
||||
|
||||
result1 := IsExist(fname)
|
||||
|
||||
CreateFile(fname)
|
||||
|
||||
result2 := IsExist(fname)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleCreateDir() {
|
||||
pwd, _ := os.Getwd()
|
||||
dirPath := pwd + "/test_xxx/"
|
||||
|
||||
result1 := IsExist(dirPath)
|
||||
|
||||
err := CreateDir(dirPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result2 := IsExist(dirPath)
|
||||
|
||||
os.Remove(dirPath)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleIsDir() {
|
||||
|
||||
result1 := IsDir("./")
|
||||
result2 := IsDir("./xxx.go")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleRemoveFile() {
|
||||
srcFile := "./text.txt"
|
||||
CreateFile(srcFile)
|
||||
|
||||
copyFile := "./text_copy.txt"
|
||||
err := CopyFile(srcFile, copyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
file, err := os.Open(copyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
result1 := IsExist(copyFile)
|
||||
result2 := file.Name()
|
||||
|
||||
os.Remove(srcFile)
|
||||
os.Remove(copyFile)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// ./text_copy.txt
|
||||
}
|
||||
|
||||
func ExampleReadFileToString() {
|
||||
fname := "./test.txt"
|
||||
CreateFile(fname)
|
||||
|
||||
f, _ := os.OpenFile(fname, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
_, err := f.WriteString("hello world")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, _ := ReadFileToString(fname)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// hello world
|
||||
}
|
||||
|
||||
func ExampleClearFile() {
|
||||
fname := "./test.txt"
|
||||
CreateFile(fname)
|
||||
|
||||
f, _ := os.OpenFile(fname, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
_, err := f.WriteString("hello world")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content1, _ := ReadFileToString(fname)
|
||||
|
||||
err = ClearFile(fname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
content2, _ := ReadFileToString(fname)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
fmt.Println(content1)
|
||||
fmt.Println(content2)
|
||||
|
||||
// Output:
|
||||
// hello world
|
||||
//
|
||||
}
|
||||
|
||||
func ExampleReadFileByLine() {
|
||||
fname := "./test.txt"
|
||||
CreateFile(fname)
|
||||
|
||||
f, _ := os.OpenFile(fname, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||
defer f.Close()
|
||||
|
||||
_, err := f.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
content, _ := ReadFileByLine(fname)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
fmt.Println(content)
|
||||
|
||||
// Output:
|
||||
// [hello world]
|
||||
}
|
||||
|
||||
func ExampleListFileNames() {
|
||||
fileList, _ := ListFileNames("../formatter/")
|
||||
fmt.Println(fileList)
|
||||
|
||||
// Output:
|
||||
// [formatter.go formatter_example_test.go formatter_test.go]
|
||||
}
|
||||
|
||||
func ExampleZip() {
|
||||
srcFile := "./test.txt"
|
||||
CreateFile(srcFile)
|
||||
|
||||
zipFile := "./test.zip"
|
||||
err := Zip(srcFile, zipFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result := IsExist(zipFile)
|
||||
|
||||
os.Remove(srcFile)
|
||||
os.Remove(zipFile)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleUnZip() {
|
||||
fname := "./test.txt"
|
||||
file, _ := os.Create(fname)
|
||||
|
||||
_, err := file.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
f, _ := os.Open(fname)
|
||||
defer f.Close()
|
||||
|
||||
mimeType := MiMeType(f)
|
||||
fmt.Println(mimeType)
|
||||
|
||||
os.Remove(fname)
|
||||
|
||||
// Output:
|
||||
// application/octet-stream
|
||||
}
|
||||
@@ -96,16 +96,6 @@ func TestCopyFile(t *testing.T) {
|
||||
os.Remove(destFile)
|
||||
}
|
||||
|
||||
func TestListFileNames(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestListFileNames")
|
||||
|
||||
filesInPath, err := ListFileNames("./")
|
||||
assert.IsNil(err)
|
||||
|
||||
expected := []string{"file.go", "file_test.go"}
|
||||
assert.Equal(expected, filesInPath)
|
||||
}
|
||||
|
||||
func TestReadFileToString(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestReadFileToString")
|
||||
|
||||
@@ -241,3 +231,13 @@ func TestMiMeType(t *testing.T) {
|
||||
assert.Equal("text/plain; charset=utf-8", MiMeType(f))
|
||||
assert.Equal("text/plain; charset=utf-8", MiMeType("./file.go"))
|
||||
}
|
||||
|
||||
func TestListFileNames(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestListFileNames")
|
||||
|
||||
filesInPath, err := ListFileNames("../formatter/")
|
||||
assert.IsNil(err)
|
||||
|
||||
expected := []string{"formatter.go", "formatter_example_test.go", "formatter_test.go"}
|
||||
assert.Equal(expected, filesInPath)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
@@ -13,6 +16,7 @@ import (
|
||||
// Comma add comma to a number value by every 3 numbers from right. ahead by symbol char.
|
||||
// if value is invalid number string eg "aa", return empty string
|
||||
// Comma("12345", "$") => "$12,345", Comma(12345, "$") => "$12,345"
|
||||
// Play: https://go.dev/play/p/eRD5k2vzUVX
|
||||
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string {
|
||||
s, err := numberToString(value)
|
||||
if err != nil {
|
||||
@@ -26,3 +30,42 @@ func Comma[T constraints.Float | constraints.Integer | string](value T, symbol s
|
||||
|
||||
return symbol + commaString(s)
|
||||
}
|
||||
|
||||
func commaString(s string) string {
|
||||
if len(s) <= 3 {
|
||||
return s
|
||||
}
|
||||
return commaString(s[:len(s)-3]) + "," + commaString(s[len(s)-3:])
|
||||
}
|
||||
|
||||
func numberToString(value any) (string, error) {
|
||||
switch reflect.TypeOf(value).Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return fmt.Sprintf("%v", value), nil
|
||||
|
||||
// todo: need to handle 12345678.9 => 1.23456789e+07
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return fmt.Sprintf("%v", value), nil
|
||||
|
||||
case reflect.String:
|
||||
{
|
||||
sv := fmt.Sprintf("%v", value)
|
||||
if strings.Contains(sv, ".") {
|
||||
_, err := strconv.ParseFloat(sv, 64)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return sv, nil
|
||||
} else {
|
||||
_, err := strconv.ParseInt(sv, 10, 64)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
return sv, nil
|
||||
}
|
||||
}
|
||||
default:
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
|
||||
18
formatter/formatter_example_test.go
Normal file
18
formatter/formatter_example_test.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package formatter
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleComma() {
|
||||
result1 := Comma("123", "")
|
||||
result2 := Comma("12345", "$")
|
||||
result3 := Comma(1234567, "¥")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 123
|
||||
// $12,345
|
||||
// ¥1,234,567
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package formatter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func commaString(s string) string {
|
||||
if len(s) <= 3 {
|
||||
return s
|
||||
}
|
||||
return commaString(s[:len(s)-3]) + "," + commaString(s[len(s)-3:])
|
||||
}
|
||||
|
||||
func numberToString(value any) (string, error) {
|
||||
switch reflect.TypeOf(value).Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return fmt.Sprintf("%v", value), nil
|
||||
|
||||
// todo: need to handle 12345678.9 => 1.23456789e+07
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return fmt.Sprintf("%v", value), nil
|
||||
|
||||
case reflect.String:
|
||||
{
|
||||
sv := fmt.Sprintf("%v", value)
|
||||
if strings.Contains(sv, ".") {
|
||||
_, err := strconv.ParseFloat(sv, 64)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return sv, nil
|
||||
} else {
|
||||
_, err := strconv.ParseInt(sv, 10, 64)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
return sv, nil
|
||||
}
|
||||
}
|
||||
default:
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,13 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// After creates a function that invokes func once it's called n or more times
|
||||
// After creates a function that invokes func once it's called n or more times.
|
||||
// Play: https://go.dev/play/p/8mQhkFmsgqs
|
||||
func After(n int, fn any) func(args ...any) []reflect.Value {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
@@ -23,7 +25,8 @@ func After(n int, fn any) func(args ...any) []reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
// Before creates a function that invokes func once it's called less than n times
|
||||
// Before creates a function that invokes func once it's called less than n times.
|
||||
// Play: https://go.dev/play/p/0HqUDIFZ3IL
|
||||
func Before(n int, fn any) func(args ...any) []reflect.Value {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
@@ -40,41 +43,48 @@ func Before(n int, fn any) func(args ...any) []reflect.Value {
|
||||
}
|
||||
}
|
||||
|
||||
// Fn is for curry function which is func(...any) any
|
||||
type Fn func(...any) any
|
||||
// CurryFn is for make curry function
|
||||
type CurryFn[T any] func(...T) T
|
||||
|
||||
// Curry make a curry function
|
||||
func (f Fn) Curry(i any) func(...any) any {
|
||||
return func(values ...any) any {
|
||||
v := append([]any{i}, values...)
|
||||
return f(v...)
|
||||
// New make a curry function for specific value.
|
||||
// Play: https://go.dev/play/p/5HopfDwANKX
|
||||
func (cf CurryFn[T]) New(val T) func(...T) T {
|
||||
return func(vals ...T) T {
|
||||
args := append([]T{val}, vals...)
|
||||
return cf(args...)
|
||||
}
|
||||
}
|
||||
|
||||
// Compose compose the functions from right to left
|
||||
func Compose(fnList ...func(...any) any) func(...any) any {
|
||||
return func(s ...any) any {
|
||||
f := fnList[0]
|
||||
restFn := fnList[1:]
|
||||
// Compose compose the functions from right to left.
|
||||
// Play: https://go.dev/play/p/KKfugD4PKYF
|
||||
func Compose[T any](fnList ...func(...T) T) func(...T) T {
|
||||
return func(args ...T) T {
|
||||
firstFn := fnList[0]
|
||||
restFns := fnList[1:]
|
||||
|
||||
if len(fnList) == 1 {
|
||||
return f(s...)
|
||||
return firstFn(args...)
|
||||
}
|
||||
|
||||
return f(Compose(restFn...)(s...))
|
||||
fn := Compose(restFns...)
|
||||
arg := fn(args...)
|
||||
|
||||
return firstFn(arg)
|
||||
}
|
||||
}
|
||||
|
||||
// Delay make the function execution after delayed time
|
||||
// Delay make the function execution after delayed time.
|
||||
// Play: https://go.dev/play/p/Ivtc2ZE-Tye
|
||||
func Delay(delay time.Duration, fn any, args ...any) {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
|
||||
time.Sleep(delay)
|
||||
invokeFunc(fn, args...)
|
||||
unsafeInvokeFunc(fn, args...)
|
||||
}
|
||||
|
||||
// Debounced creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.
|
||||
// Play: https://go.dev/play/p/absuEGB_GN7
|
||||
func Debounced(fn func(), duration time.Duration) func() {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
@@ -92,7 +102,8 @@ func Debounced(fn func(), duration time.Duration) func() {
|
||||
return func() { timer.Reset(duration) }
|
||||
}
|
||||
|
||||
// Schedule invoke function every duration time, util close the returned bool chan
|
||||
// Schedule invoke function every duration time, util close the returned bool channel.
|
||||
// Play: https://go.dev/play/p/hbON-Xeyn5N
|
||||
func Schedule(d time.Duration, fn any, args ...any) chan bool {
|
||||
// Catch programming error while constructing the closure
|
||||
mustBeFunction(fn)
|
||||
@@ -114,6 +125,7 @@ func Schedule(d time.Duration, fn any, args ...any) chan bool {
|
||||
|
||||
// Pipeline takes a list of functions and returns a function whose param will be passed into
|
||||
// the functions one by one.
|
||||
// Play: https://go.dev/play/p/mPdUVvj6HD6
|
||||
func Pipeline[T any](funcs ...func(T) T) func(T) T {
|
||||
return func(arg T) (result T) {
|
||||
result = arg
|
||||
@@ -123,3 +135,19 @@ func Pipeline[T any](funcs ...func(T) T) func(T) T {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func unsafeInvokeFunc(fn any, args ...any) []reflect.Value {
|
||||
fv := reflect.ValueOf(fn)
|
||||
params := make([]reflect.Value, len(args))
|
||||
for i, item := range args {
|
||||
params[i] = reflect.ValueOf(item)
|
||||
}
|
||||
return fv.Call(params)
|
||||
}
|
||||
|
||||
func mustBeFunction(function any) {
|
||||
v := reflect.ValueOf(function)
|
||||
if v.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||
}
|
||||
}
|
||||
|
||||
147
function/function_example_test.go
Normal file
147
function/function_example_test.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleAfter() {
|
||||
fn := After(2, func() {
|
||||
fmt.Println("test")
|
||||
})
|
||||
|
||||
fn()
|
||||
fn()
|
||||
|
||||
// Output:
|
||||
// test
|
||||
}
|
||||
|
||||
func ExampleBefore() {
|
||||
fn := Before(2, func() {
|
||||
fmt.Println("test")
|
||||
})
|
||||
|
||||
fn()
|
||||
fn()
|
||||
fn()
|
||||
fn()
|
||||
|
||||
// Output:
|
||||
// test
|
||||
// test
|
||||
}
|
||||
|
||||
func ExampleCurryFn_New() {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
|
||||
var addCurry CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
result := add1(2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleCompose() {
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
transform := Compose(toUpper, toLower)
|
||||
|
||||
result := transform("aBCde")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// ABCDE
|
||||
}
|
||||
|
||||
func ExampleDelay() {
|
||||
var print = func(s string) {
|
||||
fmt.Println(s)
|
||||
}
|
||||
|
||||
Delay(2*time.Second, print, "hello")
|
||||
|
||||
// Output:
|
||||
// hello
|
||||
}
|
||||
|
||||
func ExampleDebounced() {
|
||||
count := 0
|
||||
add := func() {
|
||||
count++
|
||||
}
|
||||
|
||||
debouncedAdd := Debounced(add, 50*time.Microsecond)
|
||||
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
debouncedAdd()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
debouncedAdd()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleSchedule() {
|
||||
count := 0
|
||||
|
||||
increase := func() {
|
||||
count++
|
||||
}
|
||||
|
||||
stop := Schedule(2*time.Second, increase)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
close(stop)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExamplePipeline() {
|
||||
addOne := func(x int) int {
|
||||
return x + 1
|
||||
}
|
||||
double := func(x int) int {
|
||||
return 2 * x
|
||||
}
|
||||
square := func(x int) int {
|
||||
return x * x
|
||||
}
|
||||
|
||||
fn := Pipeline(addOne, double, square)
|
||||
|
||||
result := fn(2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 36
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package function
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func invokeFunc(fn any, args ...any) []reflect.Value {
|
||||
fv := functionValue(fn)
|
||||
params := make([]reflect.Value, len(args))
|
||||
for i, item := range args {
|
||||
params[i] = reflect.ValueOf(item)
|
||||
}
|
||||
return fv.Call(params)
|
||||
}
|
||||
|
||||
func unsafeInvokeFunc(fn any, args ...any) []reflect.Value {
|
||||
fv := reflect.ValueOf(fn)
|
||||
params := make([]reflect.Value, len(args))
|
||||
for i, item := range args {
|
||||
params[i] = reflect.ValueOf(item)
|
||||
}
|
||||
return fv.Call(params)
|
||||
}
|
||||
|
||||
func functionValue(function any) reflect.Value {
|
||||
v := reflect.ValueOf(function)
|
||||
if v.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func mustBeFunction(function any) {
|
||||
v := reflect.ValueOf(function)
|
||||
if v.Kind() != reflect.Func {
|
||||
panic(fmt.Sprintf("Invalid function type, value of type %T", function))
|
||||
}
|
||||
}
|
||||
@@ -62,24 +62,26 @@ func TestCurry(t *testing.T) {
|
||||
add := func(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
var addCurry Fn = func(values ...any) any {
|
||||
return add(values[0].(int), values[1].(int))
|
||||
var addCurry CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
assert.Equal(3, add1(2))
|
||||
}
|
||||
|
||||
func TestCompose(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestCompose")
|
||||
|
||||
toUpper := func(a ...any) any {
|
||||
return strings.ToUpper(a[0].(string))
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
toLower := func(a ...any) any {
|
||||
return strings.ToLower(a[0].(string))
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
|
||||
expected := toUpper(toLower("aBCde"))
|
||||
|
||||
cf := Compose(toUpper, toLower)
|
||||
res := cf("aBCde")
|
||||
|
||||
|
||||
@@ -3,12 +3,18 @@ package function
|
||||
import "time"
|
||||
|
||||
// Watcher is used for record code excution time
|
||||
// Play: https://go.dev/play/p/l2yrOpCLd1I
|
||||
type Watcher struct {
|
||||
startTime int64
|
||||
stopTime int64
|
||||
excuting bool
|
||||
}
|
||||
|
||||
// Start the watch timer.
|
||||
func NewWatcher() *Watcher {
|
||||
return &Watcher{}
|
||||
}
|
||||
|
||||
// Start the watch timer.
|
||||
func (w *Watcher) Start() {
|
||||
w.startTime = time.Now().UnixNano()
|
||||
|
||||
22
function/watcher_example_test.go
Normal file
22
function/watcher_example_test.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package function
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleWatcher() {
|
||||
w := NewWatcher()
|
||||
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
|
||||
w.Stop()
|
||||
|
||||
// eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
|
||||
fmt.Println("foo")
|
||||
|
||||
w.Reset()
|
||||
|
||||
// Output:
|
||||
// foo
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
func TestWatcher(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestWatcher")
|
||||
|
||||
w := &Watcher{}
|
||||
w := NewWatcher()
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
package iterator
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
@@ -102,21 +104,15 @@ func (iter *sliceIterator[T]) HasNext() bool {
|
||||
|
||||
func (iter *sliceIterator[T]) Next() (T, bool) {
|
||||
iter.index++
|
||||
|
||||
ok := iter.index >= 0 && iter.index < len(iter.slice)
|
||||
|
||||
var item T
|
||||
if ok {
|
||||
item = iter.slice[iter.index]
|
||||
}
|
||||
return item, ok
|
||||
|
||||
// if len(iter.slice) == 0 {
|
||||
// var zero T
|
||||
// return zero, false
|
||||
// }
|
||||
// iter.index++
|
||||
// item := iter.slice[0]
|
||||
// iter.slice = iter.slice[1:]
|
||||
// return item, true
|
||||
return item, ok
|
||||
}
|
||||
|
||||
// Prev implements PrevIterator.
|
||||
@@ -171,3 +167,41 @@ func (iter *rangeIterator[T]) Next() (T, bool) {
|
||||
iter.start += iter.step
|
||||
return num, true
|
||||
}
|
||||
|
||||
// FromRange creates a iterator which returns the numeric range between start inclusive and end
|
||||
// exclusive by the step size. start should be less than end, step shoud be positive.
|
||||
func FromChannel[T any](channel <-chan T) Iterator[T] {
|
||||
return &channelIterator[T]{channel: channel}
|
||||
}
|
||||
|
||||
type channelIterator[T any] struct {
|
||||
channel <-chan T
|
||||
}
|
||||
|
||||
func (iter *channelIterator[T]) Next() (T, bool) {
|
||||
item, ok := <-iter.channel
|
||||
return item, ok
|
||||
}
|
||||
|
||||
func (iter *channelIterator[T]) HasNext() bool {
|
||||
return len(iter.channel) == 0
|
||||
}
|
||||
|
||||
// ToChannel create a new goroutine to pull items from the channel iterator to the returned channel.
|
||||
func ToChannel[T any](ctx context.Context, iter Iterator[T], buffer int) <-chan T {
|
||||
result := make(chan T, buffer)
|
||||
|
||||
go func() {
|
||||
defer close(result)
|
||||
|
||||
for item, ok := iter.Next(); ok; item, ok = iter.Next() {
|
||||
select {
|
||||
case result <- item:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package iterator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
@@ -47,4 +48,56 @@ func TestSliceIterator(t *testing.T) {
|
||||
assert.Equal(false, ok)
|
||||
})
|
||||
|
||||
t.Run("slice iterator ToSlice: ", func(t *testing.T) {
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
item, _ := iter.Next()
|
||||
assert.Equal(1, item)
|
||||
|
||||
data := ToSlice(iter)
|
||||
assert.Equal([]int{2, 3, 4}, data)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestRangeIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRangeIterator")
|
||||
|
||||
t.Run("range iterator: ", func(t *testing.T) {
|
||||
iter := FromRange(1, 4, 1)
|
||||
|
||||
item, ok := iter.Next()
|
||||
assert.Equal(1, item)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
item, ok = iter.Next()
|
||||
assert.Equal(2, item)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
item, ok = iter.Next()
|
||||
assert.Equal(3, item)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
_, ok = iter.Next()
|
||||
assert.Equal(false, ok)
|
||||
assert.Equal(false, iter.HasNext())
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestChannelIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRangeIterator")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
iter = FromChannel(ToChannel(ctx, iter, 0))
|
||||
item, ok := iter.Next()
|
||||
assert.Equal(1, item)
|
||||
assert.Equal(true, ok)
|
||||
assert.Equal(true, iter.HasNext())
|
||||
|
||||
cancel()
|
||||
|
||||
_, ok = iter.Next()
|
||||
assert.Equal(false, ok)
|
||||
}
|
||||
|
||||
@@ -59,3 +59,81 @@ func (fr *filterIterator[T]) Next() (T, bool) {
|
||||
func (fr *filterIterator[T]) HasNext() bool {
|
||||
return fr.iter.HasNext()
|
||||
}
|
||||
|
||||
// Join creates an iterator that join all elements of iters[0], then all elements of iters[1] and so on.
|
||||
func Join[T any](iters ...Iterator[T]) Iterator[T] {
|
||||
return &joinIterator[T]{
|
||||
iters: iters,
|
||||
}
|
||||
}
|
||||
|
||||
type joinIterator[T any] struct {
|
||||
iters []Iterator[T]
|
||||
}
|
||||
|
||||
func (iter *joinIterator[T]) Next() (T, bool) {
|
||||
for len(iter.iters) > 0 {
|
||||
item, ok := iter.iters[0].Next()
|
||||
if ok {
|
||||
return item, true
|
||||
}
|
||||
iter.iters = iter.iters[1:]
|
||||
}
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
|
||||
func (iter *joinIterator[T]) HasNext() bool {
|
||||
if len(iter.iters) == 0 {
|
||||
return false
|
||||
}
|
||||
if len(iter.iters) == 1 {
|
||||
return iter.iters[0].HasNext()
|
||||
}
|
||||
|
||||
result := iter.iters[0].HasNext()
|
||||
|
||||
for i := 1; i < len(iter.iters); i++ {
|
||||
it := iter.iters[i]
|
||||
hasNext := it.HasNext()
|
||||
result = result || hasNext
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Reduce reduces iter to a single value using the reduction function reducer
|
||||
func Reduce[T any, U any](iter Iterator[T], initial U, reducer func(U, T) U) U {
|
||||
acc := initial
|
||||
|
||||
for item, ok := iter.Next(); ok; item, ok = iter.Next() {
|
||||
acc = reducer(acc, item)
|
||||
}
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
func Take[T any](it Iterator[T], num int) Iterator[T] {
|
||||
return &takeIterator[T]{it: it, num: num}
|
||||
}
|
||||
|
||||
type takeIterator[T any] struct {
|
||||
it Iterator[T]
|
||||
num int
|
||||
}
|
||||
|
||||
func (iter *takeIterator[T]) Next() (T, bool) {
|
||||
if iter.num <= 0 {
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
item, ok := iter.it.Next()
|
||||
if ok {
|
||||
iter.num--
|
||||
}
|
||||
return item, ok
|
||||
}
|
||||
|
||||
func (iter *takeIterator[T]) HasNext() bool {
|
||||
return iter.num > 0
|
||||
}
|
||||
|
||||
73
iterator/operation_test.go
Normal file
73
iterator/operation_test.go
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2022 dudaodong@gmail.com. All rights resulterved.
|
||||
// Use of this source code is governed by MIT license
|
||||
|
||||
// Package iterator provides a way to iterate over values stored in containers.
|
||||
// note:
|
||||
// 1. Full feature iterator is complicated, this package is just a experiment to explore how iterators could work in Go.
|
||||
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
|
||||
// 3. It is currently under development, unstable, and will not be completed for some time in the future.
|
||||
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
|
||||
// Hope that Go can support iterator in future. see https://github.com/golang/go/discussions/54245 and https://github.com/golang/go/discussions/56413
|
||||
package iterator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/v2/internal"
|
||||
)
|
||||
|
||||
func TestMapIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestMapIterator")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
iter = Map(iter, func(n int) int { return n / 2 })
|
||||
|
||||
result := ToSlice(iter)
|
||||
assert.Equal([]int{0, 1, 1, 2}, result)
|
||||
}
|
||||
|
||||
func TestFilterIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFilterIterator")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
|
||||
iter = Filter(iter, func(n int) bool { return n < 3 })
|
||||
|
||||
result := ToSlice(iter)
|
||||
assert.Equal([]int{1, 2}, result)
|
||||
}
|
||||
|
||||
func TestJoinIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestJoinIterator")
|
||||
|
||||
iter1 := FromSlice([]int{1, 2})
|
||||
iter2 := FromSlice([]int{3, 4})
|
||||
|
||||
iter := Join(iter1, iter2)
|
||||
|
||||
item, ok := iter.Next()
|
||||
assert.Equal(1, item)
|
||||
assert.Equal(true, ok)
|
||||
|
||||
assert.Equal([]int{2, 3, 4}, ToSlice(iter))
|
||||
}
|
||||
|
||||
func TestReduce(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestReduce")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4})
|
||||
sum := Reduce(iter, 0, func(a, b int) int { return a + b })
|
||||
assert.Equal(10, sum)
|
||||
}
|
||||
|
||||
func TestTakeIterator(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestTakeIterator")
|
||||
|
||||
iter := FromSlice([]int{1, 2, 3, 4, 5})
|
||||
|
||||
iter = Take(iter, 3)
|
||||
|
||||
result := ToSlice(iter)
|
||||
assert.Equal([]int{1, 2, 3}, result)
|
||||
}
|
||||
@@ -6,7 +6,8 @@ package maputil
|
||||
|
||||
import "reflect"
|
||||
|
||||
// Keys returns a slice of the map's keys
|
||||
// Keys returns a slice of the map's keys.
|
||||
// Play: https://go.dev/play/p/xNB5bTb97Wd
|
||||
func Keys[K comparable, V any](m map[K]V) []K {
|
||||
keys := make([]K, len(m))
|
||||
|
||||
@@ -19,7 +20,8 @@ func Keys[K comparable, V any](m map[K]V) []K {
|
||||
return keys
|
||||
}
|
||||
|
||||
// Values returns a slice of the map's values
|
||||
// Values returns a slice of the map's values.
|
||||
// Play: https://go.dev/play/p/CBKdUc5FTW6
|
||||
func Values[K comparable, V any](m map[K]V) []V {
|
||||
values := make([]V, len(m))
|
||||
|
||||
@@ -32,7 +34,8 @@ func Values[K comparable, V any](m map[K]V) []V {
|
||||
return values
|
||||
}
|
||||
|
||||
// Merge maps, next key will overwrite previous key
|
||||
// Merge maps, next key will overwrite previous key.
|
||||
// Play: https://go.dev/play/p/H95LENF1uB-
|
||||
func Merge[K comparable, V any](maps ...map[K]V) map[K]V {
|
||||
result := make(map[K]V, 0)
|
||||
|
||||
@@ -45,14 +48,16 @@ func Merge[K comparable, V any](maps ...map[K]V) map[K]V {
|
||||
return result
|
||||
}
|
||||
|
||||
// ForEach executes iteratee funcation for every key and value pair in map
|
||||
// ForEach executes iteratee funcation for every key and value pair in map.
|
||||
// Play: https://go.dev/play/p/OaThj6iNVXK
|
||||
func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V)) {
|
||||
for k, v := range m {
|
||||
iteratee(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// Filter iterates over map, return a new map contains all key and value pairs pass the predicate function
|
||||
// Filter iterates over map, return a new map contains all key and value pairs pass the predicate function.
|
||||
// Play: https://go.dev/play/p/fSvF3wxuNG7
|
||||
func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V {
|
||||
result := make(map[K]V)
|
||||
|
||||
@@ -64,7 +69,8 @@ func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool)
|
||||
return result
|
||||
}
|
||||
|
||||
// Intersect iterates over maps, return a new map of key and value pairs in all given maps
|
||||
// Intersect iterates over maps, return a new map of key and value pairs in all given maps.
|
||||
// Play: https://go.dev/play/p/Zld0oj3sjcC
|
||||
func Intersect[K comparable, V any](maps ...map[K]V) map[K]V {
|
||||
if len(maps) == 0 {
|
||||
return map[K]V{}
|
||||
@@ -97,7 +103,8 @@ func Intersect[K comparable, V any](maps ...map[K]V) map[K]V {
|
||||
return result
|
||||
}
|
||||
|
||||
// Minus creates an map of whose key in mapA but not in mapB
|
||||
// Minus creates a map of whose key in mapA but not in mapB.
|
||||
// Play: https://go.dev/play/p/3u5U9K7YZ9m
|
||||
func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V {
|
||||
result := make(map[K]V)
|
||||
|
||||
@@ -109,7 +116,8 @@ func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V {
|
||||
return result
|
||||
}
|
||||
|
||||
// IsDisjoint two map are disjoint if they have no keys in common
|
||||
// IsDisjoint two map are disjoint if they have no keys in common.
|
||||
// Play: https://go.dev/play/p/N9qgYg_Ho6f
|
||||
func IsDisjoint[K comparable, V any](mapA, mapB map[K]V) bool {
|
||||
for k := range mapA {
|
||||
if _, ok := mapB[k]; ok {
|
||||
|
||||
181
maputil/map_example_test.go
Normal file
181
maputil/map_example_test.go
Normal file
@@ -0,0 +1,181 @@
|
||||
package maputil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func ExampleKeys() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
|
||||
keys := Keys(m)
|
||||
sort.Ints(keys)
|
||||
|
||||
fmt.Println(keys)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
|
||||
func ExampleValues() {
|
||||
m := map[int]string{
|
||||
1: "a",
|
||||
2: "a",
|
||||
3: "b",
|
||||
4: "c",
|
||||
5: "d",
|
||||
}
|
||||
|
||||
values := Values(m)
|
||||
sort.Strings(values)
|
||||
|
||||
fmt.Println(values)
|
||||
|
||||
// Output:
|
||||
// [a a b c d]
|
||||
}
|
||||
|
||||
func ExampleMerge() {
|
||||
m1 := map[int]string{
|
||||
1: "a",
|
||||
2: "b",
|
||||
}
|
||||
m2 := map[int]string{
|
||||
1: "c",
|
||||
3: "d",
|
||||
}
|
||||
|
||||
result := Merge(m1, m2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[1:c 2:b 3:d]
|
||||
}
|
||||
|
||||
func ExampleForEach() {
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
}
|
||||
|
||||
var sum int
|
||||
ForEach(m, func(_ string, value int) {
|
||||
sum += value
|
||||
})
|
||||
|
||||
fmt.Println(sum)
|
||||
|
||||
// Output:
|
||||
// 10
|
||||
}
|
||||
|
||||
func ExampleFilter() {
|
||||
m := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
"d": 4,
|
||||
"e": 5,
|
||||
}
|
||||
|
||||
isEven := func(_ string, value int) bool {
|
||||
return value%2 == 0
|
||||
}
|
||||
|
||||
result := Filter(m, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[b:2 d:4]
|
||||
}
|
||||
|
||||
func ExampleIntersect() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 6,
|
||||
"d": 7,
|
||||
}
|
||||
|
||||
m3 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 9,
|
||||
"e": 9,
|
||||
}
|
||||
|
||||
result1 := Intersect(m1)
|
||||
result2 := Intersect(m1, m2)
|
||||
result3 := Intersect(m1, m2, m3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// map[a:1 b:2 c:3]
|
||||
// map[a:1 b:2]
|
||||
// map[a:1]
|
||||
}
|
||||
|
||||
func ExampleMinus() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"a": 11,
|
||||
"b": 22,
|
||||
"d": 33,
|
||||
}
|
||||
|
||||
result := Minus(m1, m2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[c:3]
|
||||
}
|
||||
|
||||
func ExampleIsDisjoint() {
|
||||
m1 := map[string]int{
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
"c": 3,
|
||||
}
|
||||
|
||||
m2 := map[string]int{
|
||||
"d": 22,
|
||||
}
|
||||
|
||||
m3 := map[string]int{
|
||||
"a": 22,
|
||||
}
|
||||
|
||||
result1 := IsDisjoint(m1, m2)
|
||||
result2 := IsDisjoint(m1, m3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
@@ -13,7 +13,8 @@ import (
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
// Exponent calculate x^n
|
||||
// Exponent calculate x^n.
|
||||
// Play: https://go.dev/play/p/uF3HGNPk8wr
|
||||
func Exponent(x, n int64) int64 {
|
||||
if n == 0 {
|
||||
return 1
|
||||
@@ -28,7 +29,8 @@ func Exponent(x, n int64) int64 {
|
||||
return t * t
|
||||
}
|
||||
|
||||
// Fibonacci calculate fibonacci number before n
|
||||
// Fibonacci calculate fibonacci number before n.
|
||||
// Play: https://go.dev/play/p/IscseUNMuUc
|
||||
func Fibonacci(first, second, n int) int {
|
||||
if n <= 0 {
|
||||
return 0
|
||||
@@ -42,7 +44,8 @@ func Fibonacci(first, second, n int) int {
|
||||
}
|
||||
}
|
||||
|
||||
// Factorial calculate x!
|
||||
// Factorial calculate x!.
|
||||
// Play: https://go.dev/play/p/tt6LdOK67Nx
|
||||
func Factorial(x uint) uint {
|
||||
var f uint = 1
|
||||
for ; x > 1; x-- {
|
||||
@@ -51,18 +54,20 @@ func Factorial(x uint) uint {
|
||||
return f
|
||||
}
|
||||
|
||||
// Percent calculate the percentage of val to total
|
||||
// Percent calculate the percentage of value to total.
|
||||
// Play: https://go.dev/play/p/QQM9B13coSP
|
||||
func Percent(val, total float64, n int) float64 {
|
||||
if total == 0 {
|
||||
return float64(0)
|
||||
}
|
||||
tmp := val / total * 100
|
||||
tmp := val / total
|
||||
result := RoundToFloat(tmp, n)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// RoundToString round up to n decimal places
|
||||
// RoundToString round up to n decimal places.
|
||||
// Play: https://go.dev/play/p/kZwpBRAcllO
|
||||
func RoundToString(x float64, n int) string {
|
||||
tmp := math.Pow(10.0, float64(n))
|
||||
x *= tmp
|
||||
@@ -71,7 +76,8 @@ func RoundToString(x float64, n int) string {
|
||||
return result
|
||||
}
|
||||
|
||||
// RoundToFloat round up to n decimal places
|
||||
// RoundToFloat round up to n decimal places.
|
||||
// Play: https://go.dev/play/p/ghyb528JRJL
|
||||
func RoundToFloat(x float64, n int) float64 {
|
||||
tmp := math.Pow(10.0, float64(n))
|
||||
x *= tmp
|
||||
@@ -79,7 +85,8 @@ func RoundToFloat(x float64, n int) float64 {
|
||||
return x / tmp
|
||||
}
|
||||
|
||||
// TruncRound round off n decimal places
|
||||
// TruncRound round off n decimal places.
|
||||
// Play: https://go.dev/play/p/aumarSHIGzP
|
||||
func TruncRound(x float64, n int) float64 {
|
||||
floatStr := fmt.Sprintf("%."+strconv.Itoa(n+1)+"f", x)
|
||||
temp := strings.Split(floatStr, ".")
|
||||
@@ -93,7 +100,8 @@ func TruncRound(x float64, n int) float64 {
|
||||
return result
|
||||
}
|
||||
|
||||
// Max return max value of params
|
||||
// Max return max value of numbers.
|
||||
// Play: https://go.dev/play/p/cN8DHI0rTkH
|
||||
func Max[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
max := numbers[0]
|
||||
|
||||
@@ -106,7 +114,8 @@ func Max[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
return max
|
||||
}
|
||||
|
||||
// MaxBy search the maximum value of a slice using the given comparator function.
|
||||
// MaxBy return the maximum value of a slice using the given comparator function.
|
||||
// Play: https://go.dev/play/p/pbe2MT-7DV2
|
||||
func MaxBy[T any](slice []T, comparator func(T, T) bool) T {
|
||||
var max T
|
||||
|
||||
@@ -127,7 +136,8 @@ func MaxBy[T any](slice []T, comparator func(T, T) bool) T {
|
||||
return max
|
||||
}
|
||||
|
||||
// Min return min value of params
|
||||
// Min return min value of numbers.
|
||||
// Play: https://go.dev/play/p/21BER_mlGUj
|
||||
func Min[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
min := numbers[0]
|
||||
|
||||
@@ -140,7 +150,8 @@ func Min[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
return min
|
||||
}
|
||||
|
||||
// MinBy search the minimum value of a slice using the given comparator function.
|
||||
// MinBy return the minimum value of a slice using the given comparator function.
|
||||
// Play: https://go.dev/play/p/XuJDKrDdglW
|
||||
func MinBy[T any](slice []T, comparator func(T, T) bool) T {
|
||||
var min T
|
||||
|
||||
@@ -161,7 +172,8 @@ func MinBy[T any](slice []T, comparator func(T, T) bool) T {
|
||||
return min
|
||||
}
|
||||
|
||||
// Average return average value of numbers
|
||||
// Average return average value of numbers.
|
||||
// Play: https://go.dev/play/p/Vv7LBwER-pz
|
||||
func Average[T constraints.Integer | constraints.Float](numbers ...T) T {
|
||||
var sum T
|
||||
n := T(len(numbers))
|
||||
|
||||
187
mathutil/mathutil_exmaple_test.go
Normal file
187
mathutil/mathutil_exmaple_test.go
Normal file
@@ -0,0 +1,187 @@
|
||||
package mathutil
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleExponent() {
|
||||
result1 := Exponent(10, 0)
|
||||
result2 := Exponent(10, 1)
|
||||
result3 := Exponent(10, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 10
|
||||
// 100
|
||||
}
|
||||
|
||||
func ExampleFibonacci() {
|
||||
result1 := Fibonacci(1, 1, 1)
|
||||
result2 := Fibonacci(1, 1, 2)
|
||||
result3 := Fibonacci(1, 1, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1
|
||||
// 5
|
||||
}
|
||||
|
||||
func ExampleFactorial() {
|
||||
result1 := Factorial(1)
|
||||
result2 := Factorial(2)
|
||||
result3 := Factorial(3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExamplePercent() {
|
||||
result1 := Percent(1, 2, 2)
|
||||
result2 := Percent(0.1, 0.3, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0.5
|
||||
// 0.33
|
||||
}
|
||||
|
||||
func ExampleRoundToFloat() {
|
||||
result1 := RoundToFloat(0.124, 2)
|
||||
result2 := RoundToFloat(0.125, 2)
|
||||
result3 := RoundToFloat(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.12
|
||||
// 0.13
|
||||
// 0.125
|
||||
}
|
||||
|
||||
func ExampleRoundToString() {
|
||||
result1 := RoundToString(0.124, 2)
|
||||
result2 := RoundToString(0.125, 2)
|
||||
result3 := RoundToString(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.12
|
||||
// 0.13
|
||||
// 0.125
|
||||
}
|
||||
|
||||
func ExampleTruncRound() {
|
||||
result1 := TruncRound(0.124, 2)
|
||||
result2 := TruncRound(0.125, 2)
|
||||
result3 := TruncRound(0.125, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// 0.12
|
||||
// 0.12
|
||||
// 0.125
|
||||
}
|
||||
|
||||
func ExampleAverage() {
|
||||
result1 := Average(1, 2)
|
||||
result2 := RoundToFloat(Average(1.2, 1.4), 1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.3
|
||||
}
|
||||
|
||||
func ExampleMax() {
|
||||
result1 := Max(1, 2, 3)
|
||||
result2 := Max(1.2, 1.4, 1.1, 1.4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
// 1.4
|
||||
}
|
||||
|
||||
func ExampleMaxBy() {
|
||||
result1 := MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
|
||||
result2 := MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
|
||||
result3 := MaxBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) > len(v2)
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// abc
|
||||
// abd
|
||||
//
|
||||
}
|
||||
|
||||
func ExampleMin() {
|
||||
result1 := Min(1, 2, 3)
|
||||
result2 := Min(1.2, 1.4, 1.1, 1.4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 1.1
|
||||
}
|
||||
|
||||
func ExampleMinBy() {
|
||||
result1 := MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
|
||||
result2 := MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
|
||||
result3 := MinBy([]string{}, func(v1, v2 string) bool {
|
||||
return len(v1) < len(v2)
|
||||
})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// a
|
||||
// ab
|
||||
//
|
||||
}
|
||||
@@ -35,8 +35,8 @@ func TestFactorial(t *testing.T) {
|
||||
func TestPercent(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestPercent")
|
||||
|
||||
assert.Equal(float64(50), Percent(1, 2, 2))
|
||||
assert.Equal(float64(33.33), Percent(0.1, 0.3, 2))
|
||||
assert.Equal(0.5, Percent(1, 2, 2))
|
||||
assert.Equal(0.33, Percent(0.1, 0.3, 2))
|
||||
}
|
||||
|
||||
func TestRoundToFloat(t *testing.T) {
|
||||
|
||||
@@ -21,32 +21,32 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
//HttpGet send get http request
|
||||
// HttpGet send get http request.
|
||||
func HttpGet(url string, params ...any) (*http.Response, error) {
|
||||
return doHttpRequest(http.MethodGet, url, params...)
|
||||
}
|
||||
|
||||
//HttpPost send post http request
|
||||
// HttpPost send post http request.
|
||||
func HttpPost(url string, params ...any) (*http.Response, error) {
|
||||
return doHttpRequest(http.MethodPost, url, params...)
|
||||
}
|
||||
|
||||
//HttpPut send put http request
|
||||
// HttpPut send put http request.
|
||||
func HttpPut(url string, params ...any) (*http.Response, error) {
|
||||
return doHttpRequest(http.MethodPut, url, params...)
|
||||
}
|
||||
|
||||
//HttpDelete send delete http request
|
||||
// HttpDelete send delete http request.
|
||||
func HttpDelete(url string, params ...any) (*http.Response, error) {
|
||||
return doHttpRequest(http.MethodDelete, url, params...)
|
||||
}
|
||||
|
||||
// HttpPatch send patch http request
|
||||
// HttpPatch send patch http request.
|
||||
func HttpPatch(url string, params ...any) (*http.Response, error) {
|
||||
return doHttpRequest(http.MethodPatch, url, params...)
|
||||
}
|
||||
|
||||
// ParseHttpResponse decode http response to specified interface
|
||||
// ParseHttpResponse decode http response to specified interface.
|
||||
func ParseHttpResponse(resp *http.Response, obj any) error {
|
||||
if resp == nil {
|
||||
return errors.New("InvalidResp")
|
||||
@@ -55,7 +55,8 @@ func ParseHttpResponse(resp *http.Response, obj any) error {
|
||||
return json.NewDecoder(resp.Body).Decode(obj)
|
||||
}
|
||||
|
||||
// ConvertMapToQueryString convert map to sorted url query string
|
||||
// ConvertMapToQueryString convert map to sorted url query string.
|
||||
// Play: https://go.dev/play/p/jnNt_qoSnRi
|
||||
func ConvertMapToQueryString(param map[string]any) string {
|
||||
if param == nil {
|
||||
return ""
|
||||
|
||||
@@ -92,7 +92,8 @@ func NewHttpClientWithConfig(config *HttpClientConfig) *HttpClient {
|
||||
return client
|
||||
}
|
||||
|
||||
// SendRequest send http request
|
||||
// SendRequest send http request.
|
||||
// Play: https://go.dev/play/p/jUSgynekH7G
|
||||
func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, error) {
|
||||
err := validateRequest(request)
|
||||
if err != nil {
|
||||
@@ -128,7 +129,8 @@ func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, err
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// DecodeResponse decode response into target object
|
||||
// DecodeResponse decode response into target object.
|
||||
// Play: https://go.dev/play/p/jUSgynekH7G
|
||||
func (client *HttpClient) DecodeResponse(resp *http.Response, target any) error {
|
||||
if resp == nil {
|
||||
return errors.New("invalid target param")
|
||||
@@ -203,7 +205,8 @@ func validateRequest(req *HttpRequest) error {
|
||||
}
|
||||
|
||||
// StructToUrlValues convert struct to url valuse,
|
||||
// only convert the field which is exported and has `json` tag
|
||||
// only convert the field which is exported and has `json` tag.
|
||||
// Play: https://go.dev/play/p/pFqMkM40w9z
|
||||
func StructToUrlValues(targetStruct any) url.Values {
|
||||
rv := reflect.ValueOf(targetStruct)
|
||||
rt := reflect.TypeOf(targetStruct)
|
||||
|
||||
99
netutil/http_example_test.go
Normal file
99
netutil/http_example_test.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package netutil
|
||||
|
||||
import "fmt"
|
||||
|
||||
func ExampleHttpClient_SendRequest() {
|
||||
request := &HttpRequest{
|
||||
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
|
||||
Method: "GET",
|
||||
}
|
||||
|
||||
httpClient := NewHttpClient()
|
||||
resp, err := httpClient.SendRequest(request)
|
||||
if err != nil || resp.StatusCode != 200 {
|
||||
return
|
||||
}
|
||||
|
||||
type Todo struct {
|
||||
UserId int `json:"userId"`
|
||||
Id int `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Completed bool `json:"completed"`
|
||||
}
|
||||
|
||||
var todo Todo
|
||||
err = httpClient.DecodeResponse(resp, &todo)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(todo.Id)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleHttpClient_DecodeResponse() {
|
||||
request := &HttpRequest{
|
||||
RawURL: "https://jsonplaceholder.typicode.com/todos/1",
|
||||
Method: "GET",
|
||||
}
|
||||
|
||||
httpClient := NewHttpClient()
|
||||
resp, err := httpClient.SendRequest(request)
|
||||
if err != nil || resp.StatusCode != 200 {
|
||||
return
|
||||
}
|
||||
|
||||
type Todo struct {
|
||||
UserId int `json:"userId"`
|
||||
Id int `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Completed bool `json:"completed"`
|
||||
}
|
||||
|
||||
var todo Todo
|
||||
err = httpClient.DecodeResponse(resp, &todo)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(todo.Id)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
}
|
||||
|
||||
func ExampleStructToUrlValues() {
|
||||
type TodoQuery struct {
|
||||
Id int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
todoQuery := TodoQuery{
|
||||
Id: 1,
|
||||
Name: "Test",
|
||||
}
|
||||
todoValues := StructToUrlValues(todoQuery)
|
||||
|
||||
fmt.Println(todoValues.Get("id"))
|
||||
fmt.Println(todoValues.Get("name"))
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// Test
|
||||
}
|
||||
|
||||
func ExampleConvertMapToQueryString() {
|
||||
var m = map[string]any{
|
||||
"c": 3,
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
}
|
||||
|
||||
qs := ConvertMapToQueryString(m)
|
||||
|
||||
fmt.Println(qs)
|
||||
|
||||
// Output:
|
||||
// a=1&b=2&c=3
|
||||
}
|
||||
@@ -9,7 +9,8 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GetInternalIp return internal ipv4
|
||||
// GetInternalIp return internal ipv4.
|
||||
// Play: https://go.dev/play/p/5mbu-gFp7ei
|
||||
func GetInternalIp() string {
|
||||
addr, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
@@ -26,7 +27,8 @@ func GetInternalIp() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetRequestPublicIp return the requested public ip
|
||||
// GetRequestPublicIp return the requested public ip.
|
||||
// Play: https://go.dev/play/p/kxU-YDc_eBo
|
||||
func GetRequestPublicIp(req *http.Request) string {
|
||||
var ip string
|
||||
for _, ip = range strings.Split(req.Header.Get("X-Forwarded-For"), ",") {
|
||||
@@ -47,7 +49,8 @@ func GetRequestPublicIp(req *http.Request) string {
|
||||
}
|
||||
|
||||
// GetPublicIpInfo return public ip information
|
||||
// return the PublicIpInfo struct
|
||||
// return the PublicIpInfo struct.
|
||||
// Play: https://go.dev/play/p/YDxIfozsRHR
|
||||
func GetPublicIpInfo() (*PublicIpInfo, error) {
|
||||
resp, err := http.Get("http://ip-api.com/json/")
|
||||
if err != nil {
|
||||
@@ -69,7 +72,8 @@ func GetPublicIpInfo() (*PublicIpInfo, error) {
|
||||
return &ip, nil
|
||||
}
|
||||
|
||||
// GetIps return all ipv4 of system
|
||||
// GetIps return all ipv4 of system.
|
||||
// Play: https://go.dev/play/p/NUFfcEmukx1
|
||||
func GetIps() []string {
|
||||
var ips []string
|
||||
|
||||
@@ -89,7 +93,8 @@ func GetIps() []string {
|
||||
return ips
|
||||
}
|
||||
|
||||
// GetMacAddrs get mac address
|
||||
// GetMacAddrs get mac address.
|
||||
// Play: https://go.dev/play/p/Rq9UUBS_Xp1
|
||||
func GetMacAddrs() []string {
|
||||
var macAddrs []string
|
||||
|
||||
@@ -125,7 +130,8 @@ type PublicIpInfo struct {
|
||||
Ip string `json:"query"`
|
||||
}
|
||||
|
||||
// IsPublicIP verify a ip is public or not
|
||||
// IsPublicIP verify a ip is public or not.
|
||||
// Play: https://go.dev/play/p/nmktSQpJZnn
|
||||
func IsPublicIP(IP net.IP) bool {
|
||||
if IP.IsLoopback() || IP.IsLinkLocalMulticast() || IP.IsLinkLocalUnicast() {
|
||||
return false
|
||||
@@ -145,7 +151,8 @@ func IsPublicIP(IP net.IP) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsInternalIP verify an ip is intranet or not
|
||||
// IsInternalIP verify an ip is intranet or not.
|
||||
// Play: https://go.dev/play/p/sYGhXbgO4Cb
|
||||
func IsInternalIP(IP net.IP) bool {
|
||||
if IP.IsLoopback() {
|
||||
return true
|
||||
@@ -159,7 +166,8 @@ func IsInternalIP(IP net.IP) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// EncodeUrl encode url
|
||||
// EncodeUrl encode url.
|
||||
// Play: https://go.dev/play/p/bsZ6BRC4uKI
|
||||
func EncodeUrl(urlStr string) (string, error) {
|
||||
URL, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
|
||||
91
netutil/net_example_test.go
Normal file
91
netutil/net_example_test.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func ExampleGetInternalIp() {
|
||||
internalIp := GetInternalIp()
|
||||
|
||||
result := IsInternalIP(net.ParseIP(internalIp))
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleGetPublicIpInfo() {
|
||||
ipInfo, err := GetPublicIpInfo()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
result := IsPublicIP(net.ParseIP(ipInfo.Ip))
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleGetRequestPublicIp() {
|
||||
ip := "36.112.24.10"
|
||||
|
||||
request := http.Request{
|
||||
Method: "GET",
|
||||
Header: http.Header{
|
||||
"X-Forwarded-For": {ip},
|
||||
},
|
||||
}
|
||||
publicIp := GetRequestPublicIp(&request)
|
||||
|
||||
fmt.Println(publicIp)
|
||||
|
||||
// Output:
|
||||
// 36.112.24.10
|
||||
}
|
||||
|
||||
func ExampleIsInternalIP() {
|
||||
ip1 := IsInternalIP(net.ParseIP("127.0.0.1"))
|
||||
ip2 := IsInternalIP(net.ParseIP("192.168.0.1"))
|
||||
ip3 := IsInternalIP(net.ParseIP("36.112.24.10"))
|
||||
|
||||
fmt.Println(ip1)
|
||||
fmt.Println(ip2)
|
||||
fmt.Println(ip3)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleIsPublicIP() {
|
||||
ip1 := IsPublicIP(net.ParseIP("127.0.0.1"))
|
||||
ip2 := IsPublicIP(net.ParseIP("192.168.0.1"))
|
||||
ip3 := IsPublicIP(net.ParseIP("36.112.24.10"))
|
||||
|
||||
fmt.Println(ip1)
|
||||
fmt.Println(ip2)
|
||||
fmt.Println(ip3)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// false
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleEncodeUrl() {
|
||||
urlAddr := "http://www.lancet.com?a=1&b=[2]"
|
||||
|
||||
encodedUrl, err := EncodeUrl(urlAddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(encodedUrl)
|
||||
|
||||
// Output:
|
||||
// http://www.lancet.com?a=1&b=%5B2%5D
|
||||
}
|
||||
@@ -19,7 +19,8 @@ const (
|
||||
LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
)
|
||||
|
||||
// RandInt generate random int between min and max, maybe min, not be max
|
||||
// RandInt generate random int between min and max, maybe min, not be max.
|
||||
// Play: https://go.dev/play/p/pXyyAAI5YxD
|
||||
func RandInt(min, max int) int {
|
||||
if min == max {
|
||||
return min
|
||||
@@ -28,10 +29,12 @@ func RandInt(min, max int) int {
|
||||
min, max = max, min
|
||||
}
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
return r.Intn(max-min) + min
|
||||
}
|
||||
|
||||
// RandBytes generate random byte slice
|
||||
// RandBytes generate random byte slice.
|
||||
// Play: https://go.dev/play/p/EkiLESeXf8d
|
||||
func RandBytes(length int) []byte {
|
||||
if length < 1 {
|
||||
return []byte{}
|
||||
@@ -41,45 +44,54 @@ func RandBytes(length int) []byte {
|
||||
if _, err := io.ReadFull(crand.Reader, b); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// RandString generate random string
|
||||
// RandString generate random string of specified length.
|
||||
// Play: https://go.dev/play/p/W2xvRUXA7Mi
|
||||
func RandString(length int) string {
|
||||
return random(LETTERS, length)
|
||||
}
|
||||
|
||||
// RandUpper generate a random upper case string
|
||||
// RandUpper generate a random upper case string.
|
||||
// Play: https://go.dev/play/p/29QfOh0DVuh
|
||||
func RandUpper(length int) string {
|
||||
return random(UPPER_LETTERS, length)
|
||||
}
|
||||
|
||||
// RandLower generate a random lower case string
|
||||
// RandLower generate a random lower case string.
|
||||
// Play: https://go.dev/play/p/XJtZ471cmtI
|
||||
func RandLower(length int) string {
|
||||
return random(LOWER_LETTERS, length)
|
||||
}
|
||||
|
||||
// RandNumeral generate a random numeral string
|
||||
// RandNumeral generate a random numeral string of specified length.
|
||||
// Play: https://go.dev/play/p/g4JWVpHsJcf
|
||||
func RandNumeral(length int) string {
|
||||
return random(NUMERAL, length)
|
||||
}
|
||||
|
||||
// RandNumeralOrLetter generate a random numeral or letter string
|
||||
// RandNumeralOrLetter generate a random numeral or letter string.
|
||||
// Play: https://go.dev/play/p/19CEQvpx2jD
|
||||
func RandNumeralOrLetter(length int) string {
|
||||
return random(NUMERAL+LETTERS, length)
|
||||
}
|
||||
|
||||
// random generate a random string based on given string range
|
||||
// random generate a random string based on given string range.
|
||||
func random(s string, length int) string {
|
||||
b := make([]byte, length)
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
for i := range b {
|
||||
b[i] = s[r.Int63()%int64(len(s))]
|
||||
}
|
||||
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// UUIdV4 generate a random UUID of version 4 according to RFC 4122
|
||||
// UUIdV4 generate a random UUID of version 4 according to RFC 4122.
|
||||
// Play: https://go.dev/play/p/_Z9SFmr28ft
|
||||
func UUIdV4() (string, error) {
|
||||
uuid := make([]byte, 16)
|
||||
|
||||
|
||||
126
random/random_example_test.go
Normal file
126
random/random_example_test.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package random
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func ExampleRandInt() {
|
||||
|
||||
result := RandInt(1, 10)
|
||||
|
||||
if result >= 1 && result < 10 {
|
||||
fmt.Println("ok")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// ok
|
||||
}
|
||||
|
||||
func ExampleRandBytes() {
|
||||
bytes := RandBytes(4)
|
||||
|
||||
fmt.Println(len(bytes))
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
}
|
||||
|
||||
func ExampleRandString() {
|
||||
pattern := `^[a-zA-Z]+$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
s := RandString(6)
|
||||
|
||||
result1 := reg.MatchString(s)
|
||||
result2 := len(s)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleRandUpper() {
|
||||
pattern := `^[A-Z]+$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
s := RandUpper(6)
|
||||
|
||||
result1 := reg.MatchString(s)
|
||||
result2 := len(s)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleRandLower() {
|
||||
pattern := `^[a-z]+$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
s := RandLower(6)
|
||||
|
||||
result1 := reg.MatchString(s)
|
||||
result2 := len(s)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleRandNumeral() {
|
||||
pattern := `^[0-9]+$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
s := RandNumeral(6)
|
||||
|
||||
result1 := reg.MatchString(s)
|
||||
result2 := len(s)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleRandNumeralOrLetter() {
|
||||
pattern := `^[0-9a-zA-Z]+$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
s := RandNumeralOrLetter(6)
|
||||
|
||||
result1 := reg.MatchString(s)
|
||||
result2 := len(s)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleUUIdV4() {
|
||||
pattern := `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
s, _ := UUIdV4()
|
||||
|
||||
result := reg.MatchString(s)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
@@ -68,6 +68,7 @@ func TestRandInt(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestRandInt")
|
||||
|
||||
r1 := RandInt(1, 10)
|
||||
t.Log(r1)
|
||||
assert.GreaterOrEqual(r1, 1)
|
||||
assert.Less(r1, 10)
|
||||
|
||||
|
||||
@@ -34,21 +34,24 @@ type RetryFunc func() error
|
||||
// Option is for adding retry config
|
||||
type Option func(*RetryConfig)
|
||||
|
||||
// RetryTimes set times of retry
|
||||
// RetryTimes set times of retry.
|
||||
// Play: https://go.dev/play/p/ssfVeU2SwLO
|
||||
func RetryTimes(n uint) Option {
|
||||
return func(rc *RetryConfig) {
|
||||
rc.retryTimes = n
|
||||
}
|
||||
}
|
||||
|
||||
// RetryDuration set duration of retries
|
||||
// RetryDuration set duration of retries.
|
||||
// Play: https://go.dev/play/p/nk2XRmagfVF
|
||||
func RetryDuration(d time.Duration) Option {
|
||||
return func(rc *RetryConfig) {
|
||||
rc.retryDuration = d
|
||||
}
|
||||
}
|
||||
|
||||
// Context set retry context config
|
||||
// Context set retry context config.
|
||||
// Play: https://go.dev/play/p/xnAOOXv9GkS
|
||||
func Context(ctx context.Context) Option {
|
||||
return func(rc *RetryConfig) {
|
||||
rc.context = ctx
|
||||
@@ -56,7 +59,8 @@ func Context(ctx context.Context) Option {
|
||||
}
|
||||
|
||||
// Retry executes the retryFunc repeatedly until it was successful or canceled by the context
|
||||
// The default times of retries is 5 and the default duration between retries is 3 seconds
|
||||
// The default times of retries is 5 and the default duration between retries is 3 seconds.
|
||||
// Play: https://go.dev/play/p/nk2XRmagfVF
|
||||
func Retry(retryFunc RetryFunc, opts ...Option) error {
|
||||
config := &RetryConfig{
|
||||
retryTimes: DefaultRetryTimes,
|
||||
|
||||
93
retry/retry_example_test.go
Normal file
93
retry/retry_example_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExampleContext() {
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
|
||||
number := 0
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number > 3 {
|
||||
cancel()
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
Retry(increaseNumber,
|
||||
RetryDuration(time.Microsecond*50),
|
||||
Context(ctx),
|
||||
)
|
||||
|
||||
fmt.Println(number)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
}
|
||||
|
||||
func ExampleRetryDuration() {
|
||||
number := 0
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := Retry(increaseNumber, RetryDuration(time.Microsecond*50))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(number)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
|
||||
func ExampleRetryTimes() {
|
||||
number := 0
|
||||
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := Retry(increaseNumber, RetryTimes(2))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// Output:
|
||||
// function retry.ExampleRetryTimes.func1 run failed after 2 times retry
|
||||
}
|
||||
|
||||
func ExampleRetry() {
|
||||
number := 0
|
||||
increaseNumber := func() error {
|
||||
number++
|
||||
if number == 3 {
|
||||
return nil
|
||||
}
|
||||
return errors.New("error occurs")
|
||||
}
|
||||
|
||||
err := Retry(increaseNumber, RetryDuration(time.Microsecond*50))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(number)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
147
slice/slice.go
147
slice/slice.go
@@ -10,6 +10,7 @@ import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
@@ -21,7 +22,8 @@ var (
|
||||
memoryHashCounter = make(map[string]int)
|
||||
)
|
||||
|
||||
// Contain check if the target value is in the slice or not
|
||||
// Contain check if the target value is in the slice or not.
|
||||
// Play: https://go.dev/play/p/_454yEHcNjf
|
||||
func Contain[T comparable](slice []T, target T) bool {
|
||||
for _, item := range slice {
|
||||
if item == target {
|
||||
@@ -32,7 +34,8 @@ func Contain[T comparable](slice []T, target T) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ContainSubSlice check if the slice contain a given subslice or not
|
||||
// ContainSubSlice check if the slice contain a given subslice or not.
|
||||
// Play: https://go.dev/play/p/bcuQ3UT6Sev
|
||||
func ContainSubSlice[T comparable](slice, subSlice []T) bool {
|
||||
for _, v := range subSlice {
|
||||
if !Contain(slice, v) {
|
||||
@@ -43,7 +46,8 @@ func ContainSubSlice[T comparable](slice, subSlice []T) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Chunk creates a slice of elements split into groups the length of size
|
||||
// Chunk creates a slice of elements split into groups the length of size.
|
||||
// Play: https://go.dev/play/p/b4Pou5j2L_C
|
||||
func Chunk[T any](slice []T, size int) [][]T {
|
||||
result := [][]T{}
|
||||
|
||||
@@ -62,14 +66,15 @@ func Chunk[T any](slice []T, size int) [][]T {
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
}
|
||||
|
||||
// Compact creates an slice with all falsey values removed. The values false, nil, 0, and "" are falsey
|
||||
// Compact creates an slice with all falsey values removed. The values false, nil, 0, and "" are falsey.
|
||||
// Play: https://go.dev/play/p/pO5AnxEr3TK
|
||||
func Compact[T comparable](slice []T) []T {
|
||||
var zero T
|
||||
|
||||
result := []T{}
|
||||
|
||||
for _, v := range slice {
|
||||
if v != zero {
|
||||
result = append(result, v)
|
||||
@@ -80,6 +85,7 @@ func Compact[T comparable](slice []T) []T {
|
||||
}
|
||||
|
||||
// Concat creates a new slice concatenating slice with any additional slices.
|
||||
// Play: https://go.dev/play/p/gPt-q7zr5mk
|
||||
func Concat[T any](slice []T, slices ...[]T) []T {
|
||||
result := append([]T{}, slice...)
|
||||
|
||||
@@ -90,7 +96,8 @@ func Concat[T any](slice []T, slices ...[]T) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// Difference creates an slice of whose element in slice but not in comparedSlice
|
||||
// Difference creates an slice of whose element in slice but not in comparedSlice.
|
||||
// Play: https://go.dev/play/p/VXvadzLzhDa
|
||||
func Difference[T comparable](slice, comparedSlice []T) []T {
|
||||
result := []T{}
|
||||
|
||||
@@ -105,7 +112,8 @@ func Difference[T comparable](slice, comparedSlice []T) []T {
|
||||
|
||||
// DifferenceBy it accepts iteratee which is invoked for each element of slice
|
||||
// and values to generate the criterion by which they're compared.
|
||||
// like lodash.js differenceBy: https://lodash.com/docs/4.17.15#differenceBy,
|
||||
// like lodash.js differenceBy: https://lodash.com/docs/4.17.15#differenceBy.
|
||||
// Play: https://go.dev/play/p/DiivgwM5OnC
|
||||
func DifferenceBy[T comparable](slice []T, comparedSlice []T, iteratee func(index int, item T) T) []T {
|
||||
orginSliceAfterMap := Map(slice, iteratee)
|
||||
comparedSliceAfterMap := Map(comparedSlice, iteratee)
|
||||
@@ -120,7 +128,10 @@ func DifferenceBy[T comparable](slice []T, comparedSlice []T, iteratee func(inde
|
||||
return result
|
||||
}
|
||||
|
||||
// DifferenceWith accepts comparator which is invoked to compare elements of slice to values. The order and references of result values are determined by the first slice. The comparator is invoked with two arguments: (arrVal, othVal).
|
||||
// DifferenceWith accepts comparator which is invoked to compare elements of slice to values.
|
||||
// The order and references of result values are determined by the first slice.
|
||||
// The comparator is invoked with two arguments: (arrVal, othVal).
|
||||
// Play: https://go.dev/play/p/v2U2deugKuV
|
||||
func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(item1, item2 T) bool) []T {
|
||||
result := make([]T, 0)
|
||||
|
||||
@@ -145,7 +156,8 @@ func DifferenceWith[T any](slice []T, comparedSlice []T, comparator func(item1,
|
||||
return result
|
||||
}
|
||||
|
||||
// Equal checks if two slices are equal: the same length and all elements' order and value are equal
|
||||
// Equal checks if two slices are equal: the same length and all elements' order and value are equal.
|
||||
// Play: https://go.dev/play/p/WcRQJ37ifPa
|
||||
func Equal[T comparable](slice1, slice2 []T) bool {
|
||||
if len(slice1) != len(slice2) {
|
||||
return false
|
||||
@@ -160,7 +172,8 @@ func Equal[T comparable](slice1, slice2 []T) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// EqualWith checks if two slices are equal with comparator func
|
||||
// EqualWith checks if two slices are equal with comparator func.
|
||||
// Play: https://go.dev/play/p/b9iygtgsHI1
|
||||
func EqualWith[T, U any](slice1 []T, slice2 []U, comparator func(T, U) bool) bool {
|
||||
if len(slice1) != len(slice2) {
|
||||
return false
|
||||
@@ -176,6 +189,7 @@ func EqualWith[T, U any](slice1 []T, slice2 []U, comparator func(T, U) bool) boo
|
||||
}
|
||||
|
||||
// Every return true if all of the values in the slice pass the predicate function.
|
||||
// Play: https://go.dev/play/p/R8U6Sl-j8cD
|
||||
func Every[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
for i, v := range slice {
|
||||
if !predicate(i, v) {
|
||||
@@ -186,7 +200,8 @@ func Every[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// None return true if all the values in the slice mismatch the criteria
|
||||
// None return true if all the values in the slice mismatch the criteria.
|
||||
// Play: https://go.dev/play/p/KimdalUlC-T
|
||||
func None[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
l := 0
|
||||
for i, v := range slice {
|
||||
@@ -199,6 +214,7 @@ func None[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
}
|
||||
|
||||
// Some return true if any of the values in the list pass the predicate function.
|
||||
// Play: https://go.dev/play/p/4pO9Xf9NDGS
|
||||
func Some[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
for i, v := range slice {
|
||||
if predicate(i, v) {
|
||||
@@ -209,7 +225,8 @@ func Some[T any](slice []T, predicate func(index int, item T) bool) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Filter iterates over elements of slice, returning an slice of all elements pass the predicate function
|
||||
// Filter iterates over elements of slice, returning an slice of all elements pass the predicate function.
|
||||
// Play: https://go.dev/play/p/SdPna-7qK4T
|
||||
func Filter[T any](slice []T, predicate func(index int, item T) bool) []T {
|
||||
result := make([]T, 0)
|
||||
|
||||
@@ -222,7 +239,8 @@ func Filter[T any](slice []T, predicate func(index int, item T) bool) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// Count returns the number of occurrences of the given item in the slice
|
||||
// Count returns the number of occurrences of the given item in the slice.
|
||||
// Play: https://go.dev/play/p/Mj4oiEnQvRJ
|
||||
func Count[T comparable](slice []T, item T) int {
|
||||
count := 0
|
||||
|
||||
@@ -235,7 +253,8 @@ func Count[T comparable](slice []T, item T) int {
|
||||
return count
|
||||
}
|
||||
|
||||
// CountBy iterates over elements of slice with predicate function, returns the number of all matched elements
|
||||
// CountBy iterates over elements of slice with predicate function, returns the number of all matched elements.
|
||||
// Play: https://go.dev/play/p/tHOccTMDZCC
|
||||
func CountBy[T any](slice []T, predicate func(index int, item T) bool) int {
|
||||
count := 0
|
||||
|
||||
@@ -248,7 +267,8 @@ func CountBy[T any](slice []T, predicate func(index int, item T) bool) int {
|
||||
return count
|
||||
}
|
||||
|
||||
// GroupBy iterate over elements of the slice, each element will be group by criteria, returns two slices
|
||||
// GroupBy iterate over elements of the slice, each element will be group by criteria, returns two slices.
|
||||
// Play: https://go.dev/play/p/QVkPxzPR0iA
|
||||
func GroupBy[T any](slice []T, groupFn func(index int, item T) bool) ([]T, []T) {
|
||||
if len(slice) == 0 {
|
||||
return make([]T, 0), make([]T, 0)
|
||||
@@ -270,6 +290,7 @@ func GroupBy[T any](slice []T, groupFn func(index int, item T) bool) ([]T, []T)
|
||||
}
|
||||
|
||||
// GroupWith return a map composed of keys generated from the resultults of running each element of slice thru iteratee.
|
||||
// Play: https://go.dev/play/p/ApCvMNTLO8a
|
||||
func GroupWith[T any, U comparable](slice []T, iteratee func(item T) U) map[U][]T {
|
||||
result := make(map[U][]T)
|
||||
|
||||
@@ -285,7 +306,8 @@ func GroupWith[T any, U comparable](slice []T, iteratee func(item T) U) map[U][]
|
||||
}
|
||||
|
||||
// Find iterates over elements of slice, returning the first one that passes a truth test on predicate function.
|
||||
// If return T is nil then no items matched the predicate func
|
||||
// If return T is nil then no items matched the predicate func.
|
||||
// Play: https://go.dev/play/p/CBKeBoHVLgq
|
||||
func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
|
||||
index := -1
|
||||
|
||||
@@ -303,8 +325,10 @@ func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
|
||||
return &slice[index], true
|
||||
}
|
||||
|
||||
// FindLast iterates over elements of slice from end to begin, returning the first one that passes a truth test on predicate function.
|
||||
// If return T is nil then no items matched the predicate func
|
||||
// FindLast iterates over elements of slice from end to begin,
|
||||
// return the first one that passes a truth test on predicate function.
|
||||
// If return T is nil then no items matched the predicate func.
|
||||
// Play: https://go.dev/play/p/FFDPV_j7URd
|
||||
func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
|
||||
index := -1
|
||||
|
||||
@@ -322,7 +346,8 @@ func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, boo
|
||||
return &slice[index], true
|
||||
}
|
||||
|
||||
// Flatten flattens slice with one level
|
||||
// Flatten flattens slice with one level.
|
||||
// Play: https://go.dev/play/p/hYa3cBEevtm
|
||||
func Flatten(slice any) any {
|
||||
sv := sliceValue(slice)
|
||||
|
||||
@@ -349,7 +374,8 @@ func Flatten(slice any) any {
|
||||
return result.Interface()
|
||||
}
|
||||
|
||||
// FlattenDeep flattens slice recursive
|
||||
// FlattenDeep flattens slice recursive.
|
||||
// Play: https://go.dev/play/p/yjYNHPyCFaF
|
||||
func FlattenDeep(slice any) any {
|
||||
sv := sliceValue(slice)
|
||||
st := sliceElemType(sv.Type())
|
||||
@@ -376,7 +402,8 @@ func flattenRecursive(value reflect.Value, result reflect.Value) reflect.Value {
|
||||
return result
|
||||
}
|
||||
|
||||
// ForEach iterates over elements of slice and invokes function for each element
|
||||
// ForEach iterates over elements of slice and invokes function for each element.
|
||||
// Play: https://go.dev/play/p/DrPaa4YsHRF
|
||||
func ForEach[T any](slice []T, iteratee func(index int, item T)) {
|
||||
for i, v := range slice {
|
||||
iteratee(i, v)
|
||||
@@ -384,6 +411,7 @@ func ForEach[T any](slice []T, iteratee func(index int, item T)) {
|
||||
}
|
||||
|
||||
// Map creates an slice of values by running each element of slice thru iteratee function.
|
||||
// Play: https://go.dev/play/p/biaTefqPquw
|
||||
func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
|
||||
result := make([]U, len(slice), cap(slice))
|
||||
|
||||
@@ -395,6 +423,7 @@ func Map[T any, U any](slice []T, iteratee func(index int, item T) U) []U {
|
||||
}
|
||||
|
||||
// Reduce creates an slice of values by running each element of slice thru iteratee function.
|
||||
// Play: https://go.dev/play/p/_RfXJJWIsIm
|
||||
func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initial T) T {
|
||||
if len(slice) == 0 {
|
||||
return initial
|
||||
@@ -412,7 +441,8 @@ func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initia
|
||||
return result
|
||||
}
|
||||
|
||||
// Replace returns a copy of the slice with the first n non-overlapping instances of old replaced by new
|
||||
// Replace returns a copy of the slice with the first n non-overlapping instances of old replaced by new.
|
||||
// Play: https://go.dev/play/p/P5mZp7IhOFo
|
||||
func Replace[T comparable](slice []T, old T, new T, n int) []T {
|
||||
result := make([]T, len(slice))
|
||||
copy(result, slice)
|
||||
@@ -428,11 +458,13 @@ func Replace[T comparable](slice []T, old T, new T, n int) []T {
|
||||
}
|
||||
|
||||
// ReplaceAll returns a copy of the slice with all non-overlapping instances of old replaced by new.
|
||||
// Play: https://go.dev/play/p/CzqXMsuYUrx
|
||||
func ReplaceAll[T comparable](slice []T, old T, new T) []T {
|
||||
return Replace(slice, old, new, -1)
|
||||
}
|
||||
|
||||
// Repeat creates a slice with length n whose elements are param `item`.
|
||||
// Play: https://go.dev/play/p/1CbOmtgILUU
|
||||
func Repeat[T any](item T, n int) []T {
|
||||
result := make([]T, n)
|
||||
|
||||
@@ -444,7 +476,8 @@ func Repeat[T any](item T, n int) []T {
|
||||
}
|
||||
|
||||
// InterfaceSlice convert param to slice of interface.
|
||||
// This function is deprecated, use generics feature of go1.18+ for replacement
|
||||
// This function is deprecated, use generics feature of go1.18+ for replacement.
|
||||
// Play: https://go.dev/play/p/FdQXF0Vvqs-
|
||||
func InterfaceSlice(slice any) []any {
|
||||
sv := sliceValue(slice)
|
||||
if sv.IsNil() {
|
||||
@@ -460,7 +493,8 @@ func InterfaceSlice(slice any) []any {
|
||||
}
|
||||
|
||||
// StringSlice convert param to slice of string.
|
||||
// This function is deprecated, use generics feature of go1.18+ for replacement
|
||||
// This function is deprecated, use generics feature of go1.18+ for replacement.
|
||||
// Play: https://go.dev/play/p/W0TZDWCPFcI
|
||||
func StringSlice(slice any) []string {
|
||||
v := sliceValue(slice)
|
||||
|
||||
@@ -477,7 +511,8 @@ func StringSlice(slice any) []string {
|
||||
}
|
||||
|
||||
// IntSlice convert param to slice of int.
|
||||
// This function is deprecated, use generics feature of go1.18+ for replacement
|
||||
// This function is deprecated, use generics feature of go1.18+ for replacement.
|
||||
// Play: https://go.dev/play/p/UQDj-on9TGN
|
||||
func IntSlice(slice any) []int {
|
||||
sv := sliceValue(slice)
|
||||
|
||||
@@ -494,6 +529,7 @@ func IntSlice(slice any) []int {
|
||||
}
|
||||
|
||||
// DeleteAt delete the element of slice from start index to end index - 1.
|
||||
// Play: https://go.dev/play/p/pJ-d6MUWcvK
|
||||
func DeleteAt[T any](slice []T, start int, end ...int) []T {
|
||||
size := len(slice)
|
||||
|
||||
@@ -523,7 +559,8 @@ func DeleteAt[T any](slice []T, start int, end ...int) []T {
|
||||
return slice
|
||||
}
|
||||
|
||||
// Drop creates a slice with `n` elements dropped from the beginning when n > 0, or `n` elements dropped from the ending when n < 0
|
||||
// Drop creates a slice with `n` elements dropped from the beginning when n > 0, or `n` elements dropped from the ending when n < 0.
|
||||
// Play: https://go.dev/play/p/pJ-d6MUWcvK
|
||||
func Drop[T any](slice []T, n int) []T {
|
||||
size := len(slice)
|
||||
|
||||
@@ -543,6 +580,7 @@ func Drop[T any](slice []T, n int) []T {
|
||||
}
|
||||
|
||||
// InsertAt insert the value or other slice into slice at index.
|
||||
// Play: https://go.dev/play/p/hMLNxPEGJVE
|
||||
func InsertAt[T any](slice []T, index int, value any) []T {
|
||||
size := len(slice)
|
||||
|
||||
@@ -564,6 +602,7 @@ func InsertAt[T any](slice []T, index int, value any) []T {
|
||||
}
|
||||
|
||||
// UpdateAt update the slice element at index.
|
||||
// Play: https://go.dev/play/p/f3mh2KloWVm
|
||||
func UpdateAt[T any](slice []T, index int, value T) []T {
|
||||
size := len(slice)
|
||||
|
||||
@@ -576,6 +615,7 @@ func UpdateAt[T any](slice []T, index int, value T) []T {
|
||||
}
|
||||
|
||||
// Unique remove duplicate elements in slice.
|
||||
// Play: https://go.dev/play/p/AXw0R3ZTE6a
|
||||
func Unique[T comparable](slice []T) []T {
|
||||
result := []T{}
|
||||
|
||||
@@ -597,6 +637,7 @@ func Unique[T comparable](slice []T) []T {
|
||||
}
|
||||
|
||||
// UniqueBy call iteratee func with every item of slice, then remove duplicated.
|
||||
// Play: https://go.dev/play/p/UR323iZLDpv
|
||||
func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T {
|
||||
result := []T{}
|
||||
|
||||
@@ -609,6 +650,7 @@ func UniqueBy[T comparable](slice []T, iteratee func(item T) T) []T {
|
||||
}
|
||||
|
||||
// Union creates a slice of unique elements, in order, from all given slices.
|
||||
// Play: https://go.dev/play/p/hfXV1iRIZOf
|
||||
func Union[T comparable](slices ...[]T) []T {
|
||||
result := []T{}
|
||||
contain := map[T]struct{}{}
|
||||
@@ -625,7 +667,8 @@ func Union[T comparable](slices ...[]T) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// UnionBy is like Union, what's more it accepts iteratee which is invoked for each element of each slice
|
||||
// UnionBy is like Union, what's more it accepts iteratee which is invoked for each element of each slice.
|
||||
// Play: https://go.dev/play/p/HGKHfxKQsFi
|
||||
func UnionBy[T any, V comparable](predicate func(item T) V, slices ...[]T) []T {
|
||||
result := []T{}
|
||||
contain := map[V]struct{}{}
|
||||
@@ -643,7 +686,8 @@ func UnionBy[T any, V comparable](predicate func(item T) V, slices ...[]T) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// Merge all given slices into one slice
|
||||
// Merge all given slices into one slice.
|
||||
// Play: https://go.dev/play/p/lbjFp784r9N
|
||||
func Merge[T any](slices ...[]T) []T {
|
||||
result := make([]T, 0)
|
||||
|
||||
@@ -655,6 +699,7 @@ func Merge[T any](slices ...[]T) []T {
|
||||
}
|
||||
|
||||
// Intersection creates a slice of unique elements that included by all slices.
|
||||
// Play: https://go.dev/play/p/anJXfB5wq_t
|
||||
func Intersection[T comparable](slices ...[]T) []T {
|
||||
if len(slices) == 0 {
|
||||
return []T{}
|
||||
@@ -691,7 +736,8 @@ func Intersection[T comparable](slices ...[]T) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// SymmetricDifference oppoiste operation of intersection function
|
||||
// SymmetricDifference oppoiste operation of intersection function.
|
||||
// Play: https://go.dev/play/p/h42nJX5xMln
|
||||
func SymmetricDifference[T comparable](slices ...[]T) []T {
|
||||
if len(slices) == 0 {
|
||||
return []T{}
|
||||
@@ -717,25 +763,29 @@ func SymmetricDifference[T comparable](slices ...[]T) []T {
|
||||
return Unique(result)
|
||||
}
|
||||
|
||||
// Reverse return slice of element order is reversed to the given slice
|
||||
// Reverse return slice of element order is reversed to the given slice.
|
||||
// Play: https://go.dev/play/p/8uI8f1lwNrQ
|
||||
func Reverse[T any](slice []T) {
|
||||
for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 {
|
||||
slice[i], slice[j] = slice[j], slice[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Shuffle creates an slice of shuffled values
|
||||
// Shuffle the slice.
|
||||
// Play: https://go.dev/play/p/YHvhnWGU3Ge
|
||||
func Shuffle[T any](slice []T) []T {
|
||||
result := make([]T, len(slice))
|
||||
for i, v := range rand.Perm(len(slice)) {
|
||||
result[i] = slice[v]
|
||||
}
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
return result
|
||||
rand.Shuffle(len(slice), func(i, j int) {
|
||||
slice[i], slice[j] = slice[j], slice[i]
|
||||
})
|
||||
|
||||
return slice
|
||||
}
|
||||
|
||||
// Sort sorts a slice of any ordered type(number or string), use quick sort algrithm.
|
||||
// default sort order is ascending (asc), if want descending order, set param `sortOrder` to `desc`
|
||||
// default sort order is ascending (asc), if want descending order, set param `sortOrder` to `desc`.
|
||||
// Play: https://go.dev/play/p/V9AVjzf_4Fk
|
||||
func Sort[T constraints.Ordered](slice []T, sortOrder ...string) {
|
||||
if len(sortOrder) > 0 && sortOrder[0] == "desc" {
|
||||
quickSort(slice, 0, len(slice)-1, "desc")
|
||||
@@ -745,7 +795,8 @@ func Sort[T constraints.Ordered](slice []T, sortOrder ...string) {
|
||||
}
|
||||
|
||||
// SortBy sorts the slice in ascending order as determined by the less function.
|
||||
// This sort is not guaranteed to be stable
|
||||
// This sort is not guaranteed to be stable.
|
||||
// Play: https://go.dev/play/p/DAhLQSZEumm
|
||||
func SortBy[T any](slice []T, less func(a, b T) bool) {
|
||||
quickSortBy(slice, 0, len(slice)-1, less)
|
||||
}
|
||||
@@ -753,7 +804,8 @@ func SortBy[T any](slice []T, less func(a, b T) bool) {
|
||||
// SortByField return sorted slice by field
|
||||
// slice element should be struct, field type should be int, uint, string, or bool
|
||||
// default sortType is ascending (asc), if descending order, set sortType to desc
|
||||
// This function is deprecated, use Sort and SortBy for replacement
|
||||
// This function is deprecated, use Sort and SortBy for replacement.
|
||||
// Play: https://go.dev/play/p/fU1prOBP9p1
|
||||
func SortByField(slice any, field string, sortType ...string) error {
|
||||
sv := sliceValue(slice)
|
||||
t := sv.Type().Elem()
|
||||
@@ -823,7 +875,8 @@ func SortByField(slice any, field string, sortType ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Without creates a slice excluding all given items
|
||||
// Without creates a slice excluding all given items.
|
||||
// Play: https://go.dev/play/p/bwhEXEypThg
|
||||
func Without[T comparable](slice []T, items ...T) []T {
|
||||
if len(items) == 0 || len(slice) == 0 {
|
||||
return slice
|
||||
@@ -840,6 +893,7 @@ func Without[T comparable](slice []T, items ...T) []T {
|
||||
}
|
||||
|
||||
// IndexOf returns the index at which the first occurrence of an item is found in a slice or return -1 if the item cannot be found.
|
||||
// Play: https://go.dev/play/p/MRN1f0FpABb
|
||||
func IndexOf[T comparable](arr []T, val T) int {
|
||||
limit := 10
|
||||
// gets the hash value of the array as the key of the hash table.
|
||||
@@ -881,6 +935,7 @@ func IndexOf[T comparable](arr []T, val T) int {
|
||||
}
|
||||
|
||||
// LastIndexOf returns the index at which the last occurrence of the item is found in a slice or return -1 if the then cannot be found.
|
||||
// Play: https://go.dev/play/p/DokM4cf1IKH
|
||||
func LastIndexOf[T comparable](slice []T, item T) int {
|
||||
for i := len(slice) - 1; i > 0; i-- {
|
||||
if item == slice[i] {
|
||||
@@ -891,7 +946,8 @@ func LastIndexOf[T comparable](slice []T, item T) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
// ToSlicePointer returns a pointer to the slices of a variable parameter transformation
|
||||
// ToSlicePointer returns a pointer to the slices of a variable parameter transformation.
|
||||
// Play: https://go.dev/play/p/gx4tr6_VXSF
|
||||
func ToSlicePointer[T any](items ...T) []*T {
|
||||
result := make([]*T, len(items))
|
||||
for i := range items {
|
||||
@@ -901,7 +957,8 @@ func ToSlicePointer[T any](items ...T) []*T {
|
||||
return result
|
||||
}
|
||||
|
||||
// ToSlice returns a slices of a variable parameter transformation
|
||||
// ToSlice returns a slices of a variable parameter transformation.
|
||||
// Play: https://go.dev/play/p/YzbzVq5kscN
|
||||
func ToSlice[T any](items ...T) []T {
|
||||
result := make([]T, len(items))
|
||||
copy(result, items)
|
||||
@@ -909,7 +966,8 @@ func ToSlice[T any](items ...T) []T {
|
||||
return result
|
||||
}
|
||||
|
||||
// AppendIfAbsent only absent append the item
|
||||
// AppendIfAbsent only absent append the item.
|
||||
// Play: https://go.dev/play/p/KcC1QXQ-RkL
|
||||
func AppendIfAbsent[T comparable](slice []T, item T) []T {
|
||||
if !Contain(slice, item) {
|
||||
slice = append(slice, item)
|
||||
@@ -917,7 +975,8 @@ func AppendIfAbsent[T comparable](slice []T, item T) []T {
|
||||
return slice
|
||||
}
|
||||
|
||||
// KeyBy converts a slice to a map based on a callback function
|
||||
// KeyBy converts a slice to a map based on a callback function.
|
||||
// Play: https://go.dev/play/p/uXod2LWD1Kg
|
||||
func KeyBy[T any, U comparable](slice []T, iteratee func(item T) U) map[U]T {
|
||||
result := make(map[U]T, len(slice))
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user