mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-05 05:12:26 +08:00
Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
1227
README_zh-CN.md
1227
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: Todo
|
||||
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: Todo
|
||||
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: Todo
|
||||
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: Todo
|
||||
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: Todo
|
||||
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: Todo
|
||||
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: Todo
|
||||
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: Todo
|
||||
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: Todo
|
||||
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: Todo
|
||||
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)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -570,6 +570,8 @@ 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>
|
||||
|
||||
@@ -586,10 +588,14 @@ func main() {
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
cache.Put(3, 3)
|
||||
|
||||
_, ok := cache.Get(0) // ok -> false
|
||||
fmt.Println(cache.Len()) // 3
|
||||
|
||||
v, ok := cache.Get(1) // v->1, ok->true
|
||||
v, ok := cache.Get(1)
|
||||
fmt.Println(v, ok) // 1 true
|
||||
|
||||
ok = cache.Delete(1)
|
||||
fmt.Println(ok) // true
|
||||
}
|
||||
```
|
||||
@@ -570,6 +570,8 @@ 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>
|
||||
|
||||
@@ -586,10 +588,14 @@ func main() {
|
||||
|
||||
cache.Put(1, 1)
|
||||
cache.Put(2, 2)
|
||||
cache.Put(3, 3)
|
||||
|
||||
_, ok := cache.Get(0) // ok -> false
|
||||
fmt.Println(cache.Len()) // 3
|
||||
|
||||
v, ok := cache.Get(1) // v->1, ok->true
|
||||
v, ok := cache.Get(1)
|
||||
fmt.Println(v, ok) // 1 true
|
||||
|
||||
ok = cache.Delete(1)
|
||||
fmt.Println(ok) // 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,7 +57,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
}
|
||||
```
|
||||
|
||||
@@ -70,7 +70,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>
|
||||
|
||||
@@ -87,25 +87,30 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
genVals := func() <-chan <-chan any {
|
||||
chanStream := make(chan (<-chan any))
|
||||
c := concurrency.NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
out := make(chan (<-chan int))
|
||||
go func() {
|
||||
defer close(chanStream)
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan any, 1)
|
||||
defer close(out)
|
||||
for i := 1; i <= 5; i++ {
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
out <- stream
|
||||
}
|
||||
}()
|
||||
return chanStream
|
||||
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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -114,12 +119,12 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -136,17 +141,17 @@ func main() {
|
||||
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
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -154,12 +159,12 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -176,26 +181,30 @@ func main() {
|
||||
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
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### <span id="Generate">Generate</span>
|
||||
|
||||
### <span id="RepeatFn">RepeatFn</span>
|
||||
|
||||
<p>Return a chan, excutes fn repeatly, and put the result into retruned chan until cancel context.</p>
|
||||
<p>Creates a channel, then put values into the channel.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
|
||||
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>Example:</b>
|
||||
|
||||
@@ -212,16 +221,58 @@ func main() {
|
||||
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)
|
||||
c := concurrency.NewChannel[int]()
|
||||
intStream := c.Generate(ctx, 1, 2, 3)
|
||||
|
||||
for v := range dataStream {
|
||||
fmt.Println(v) //a, a, a
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="RepeatFn">RepeatFn</span>
|
||||
|
||||
<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[T]) RepeatFn(ctx context.Context, fn func() 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()
|
||||
|
||||
fn := func() string {
|
||||
return "hello"
|
||||
}
|
||||
|
||||
c := concurrency.NewChannel[string]()
|
||||
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// hello
|
||||
// hello
|
||||
// hello
|
||||
}
|
||||
```
|
||||
|
||||
@@ -234,7 +285,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>
|
||||
|
||||
@@ -249,7 +300,7 @@ import (
|
||||
|
||||
func main() {
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan interface{})
|
||||
c := make(chan any)
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
@@ -259,13 +310,11 @@ func main() {
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[any]()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
sig(3*time.Second),
|
||||
sig(4*time.Second),
|
||||
sig(5*time.Second),
|
||||
)
|
||||
|
||||
fmt.Println("done after %v", time.Since(start)) //1.003s
|
||||
@@ -282,7 +331,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>
|
||||
|
||||
@@ -299,12 +348,16 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -313,12 +366,12 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -335,7 +388,7 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan any, 5)
|
||||
numbers := make(chan int, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
@@ -343,12 +396,16 @@ func main() {
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -356,12 +413,12 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -378,13 +435,19 @@ func main() {
|
||||
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,7 +57,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[int]()
|
||||
}
|
||||
```
|
||||
|
||||
@@ -65,12 +65,12 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -84,28 +84,33 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
genVals := func() <-chan <-chan any {
|
||||
chanStream := make(chan (<-chan any))
|
||||
c := concurrency.NewChannel[int]()
|
||||
genVals := func() <-chan <-chan int {
|
||||
out := make(chan (<-chan int))
|
||||
go func() {
|
||||
defer close(chanStream)
|
||||
for i := 0; i < 10; i++ {
|
||||
stream := make(chan any, 1)
|
||||
defer close(out)
|
||||
for i := 1; i <= 5; i++ {
|
||||
stream := make(chan int, 1)
|
||||
stream <- i
|
||||
close(stream)
|
||||
chanStream <- stream
|
||||
out <- stream
|
||||
}
|
||||
}()
|
||||
return chanStream
|
||||
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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -114,12 +119,12 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -133,33 +138,33 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
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>
|
||||
### <span id="Generate">Generate</span>
|
||||
|
||||
<p>返回一个chan,将参数`values`重复放入chan,直到取消上下文。</p>
|
||||
<p>根据传入的值,生成channel.</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
|
||||
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
|
||||
```
|
||||
<b>例子:</b>
|
||||
|
||||
@@ -173,15 +178,58 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
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.Generate(ctx, 1, 2, 3)
|
||||
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
fmt.Println(<-intStream)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 3
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Repeat">Repeat</span>
|
||||
|
||||
<p>返回一个channel,将参数`values`重复放入channel,直到取消上下文。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func (c *Channel[T]) Repeat(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.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||
|
||||
for v := range intStream {
|
||||
fmt.Println(v) //1, 2, 1, 2, 1
|
||||
fmt.Println(v)
|
||||
}
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
```
|
||||
|
||||
@@ -190,12 +238,12 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -209,19 +257,23 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
fn := func() any {
|
||||
s := "a"
|
||||
return s
|
||||
fn := func() string {
|
||||
return "hello"
|
||||
}
|
||||
c := concurrency.NewChannel()
|
||||
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
||||
|
||||
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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -229,12 +281,12 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -249,7 +301,7 @@ import (
|
||||
|
||||
func main() {
|
||||
sig := func(after time.Duration) <-chan any {
|
||||
c := make(chan interface{})
|
||||
c := make(chan any)
|
||||
go func() {
|
||||
defer close(c)
|
||||
time.Sleep(after)
|
||||
@@ -259,13 +311,11 @@ func main() {
|
||||
|
||||
start := time.Now()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
c := concurrency.NewChannel[any]()
|
||||
<-c.Or(
|
||||
sig(1*time.Second),
|
||||
sig(2*time.Second),
|
||||
sig(3*time.Second),
|
||||
sig(4*time.Second),
|
||||
sig(5*time.Second),
|
||||
)
|
||||
|
||||
fmt.Println("done after %v", time.Since(start)) //1.003s
|
||||
@@ -277,12 +327,12 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -299,12 +349,16 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -313,12 +367,12 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -335,7 +389,7 @@ func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
numbers := make(chan any, 5)
|
||||
numbers := make(chan int, 5)
|
||||
numbers <- 1
|
||||
numbers <- 2
|
||||
numbers <- 3
|
||||
@@ -343,12 +397,16 @@ func main() {
|
||||
numbers <- 5
|
||||
defer close(numbers)
|
||||
|
||||
c := concurrency.NewChannel()
|
||||
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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -356,12 +414,12 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -378,13 +436,19 @@ func main() {
|
||||
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)
|
||||
|
||||
@@ -120,7 +121,7 @@ func main() {
|
||||
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -148,7 +149,7 @@ func main() {
|
||||
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -176,7 +177,7 @@ func main() {
|
||||
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -197,14 +198,40 @@ 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(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>
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
- [Or](#Or)
|
||||
- [Xor](#Generate)
|
||||
- [Nor](#Nor)
|
||||
- [Xnor](#Xnor)
|
||||
- [Nand](#Nand)
|
||||
- [TernaryOperator](#TernaryOperator)
|
||||
|
||||
@@ -196,12 +197,38 @@ 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(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>
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -138,7 +138,7 @@ func main() {
|
||||
|
||||
### <span id="ToBytes">ToBytes</span>
|
||||
|
||||
<p>Convert interface to byte slice.</p>
|
||||
<p>Convert value to byte slice.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -200,7 +200,7 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -238,7 +238,7 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -271,7 +271,7 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -332,7 +332,7 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
|
||||
@@ -522,7 +522,7 @@ func main() {
|
||||
|
||||
### <span id="DecodeByte">DecodeByte</span>
|
||||
|
||||
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例子</p>
|
||||
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -5,10 +5,8 @@ cryptor加密包支持数据加密和解密,获取md5,hash值。支持base64
|
||||
|
||||
## 源码:
|
||||
|
||||
- [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>
|
||||
|
||||
@@ -186,7 +184,7 @@ func main() {
|
||||
|
||||
### <span id="AesCtrCrypt">AesCtrCrypt</span>
|
||||
|
||||
<p>使用AES CTR算法模式加密/解密数据. 参数`key`的长度是16, 24 or 32。</p>
|
||||
<p>使用AES CTR算法模式加密/解密数据,参数`key`的长度是16, 24 or 32。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
|
||||
@@ -377,7 +377,7 @@ func main() {
|
||||
```
|
||||
|
||||
### <span id="EndOfDay">EndOfDay</span>
|
||||
<p>返回指定时间的当天结束时间.</p>
|
||||
<p>返回指定时间的当天结束时间</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -541,7 +541,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="GetNowDateTime">GetNowDateTime</span>
|
||||
<p>获取当时日期和时间,返回格式:yyyy-mm-dd hh:mm:ss.</p>
|
||||
<p>获取当时日期和时间,返回格式:yyyy-mm-dd hh:mm:ss</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -568,7 +568,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span>
|
||||
<p>获取零时时间戳(timestamp of 00:00).</p>
|
||||
<p>获取零时时间戳(timestamp of 00:00)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -595,7 +595,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="GetNightTimestamp">GetNightTimestamp</span>
|
||||
<p>获取午夜时间戳(timestamp of 23:59).</p>
|
||||
<p>获取午夜时间戳(timestamp of 23:59)</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="CopyFile">CopyFile</span>
|
||||
<p>拷贝文件,会覆盖原有的拷贝文件</p>
|
||||
<p>拷贝文件,会覆盖原有的文件</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -261,7 +261,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="IsDir">IsDir</span>
|
||||
<p>判断目录是否存在</p>
|
||||
<p>判断参数是否是目录</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
## Index
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [Curry](#Curry)
|
||||
- [CurryFn](#CurryFn)
|
||||
- [Compose](#Compose)
|
||||
- [Debounced](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
@@ -125,15 +125,15 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="Curry">Curry</span>
|
||||
### <span id="CurryFn">CurryFn</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>
|
||||
|
||||
@@ -149,12 +149,15 @@ 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))
|
||||
|
||||
var addCurry CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
result := add1(2)
|
||||
fmt.Println(result) //3
|
||||
|
||||
fmt.Println(result) //3
|
||||
}
|
||||
```
|
||||
|
||||
@@ -167,7 +170,7 @@ 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>
|
||||
|
||||
@@ -180,17 +183,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
add1 := func(v ...any) any {
|
||||
return v[0].(int) + 1
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
add2 := func(v ...any) any {
|
||||
return v[0].(int) + 2
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
transform := Compose(toUpper, toLower)
|
||||
|
||||
add3 := function.Compose(add1, add2)
|
||||
result := add3(1)
|
||||
result := transform("aBCde")
|
||||
|
||||
fmt.Println(result) //4
|
||||
fmt.Println(result) //ABCDE
|
||||
}
|
||||
```
|
||||
|
||||
@@ -259,9 +262,9 @@ import (
|
||||
|
||||
func main() {
|
||||
var print = func(s string) {
|
||||
fmt.Println(count) //test delay
|
||||
fmt.Println(count) //delay 2 seconds
|
||||
}
|
||||
function.Delay(2*time.Second, print, "test delay")
|
||||
function.Delay(2*time.Second, print, "delay 2 seconds")
|
||||
}
|
||||
```
|
||||
|
||||
@@ -332,9 +335,9 @@ func main() {
|
||||
return x * x
|
||||
}
|
||||
|
||||
f := Pipeline(addOne, double, square)
|
||||
fn := Pipeline(addOne, double, square)
|
||||
|
||||
fmt.Println(f(2)) //36
|
||||
fmt.Println(fn(2)) //36
|
||||
}
|
||||
```
|
||||
|
||||
@@ -351,6 +354,7 @@ type Watcher struct {
|
||||
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
|
||||
@@ -367,7 +371,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := &function.Watcher{}
|
||||
w := function.NewWatcher()
|
||||
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
@@ -377,14 +382,10 @@ func main() {
|
||||
w.Stop()
|
||||
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
|
||||
fmt.Println(eapsedTime)
|
||||
|
||||
w.Reset()
|
||||
|
||||
fmt.Println(w.excuting) //false
|
||||
|
||||
fmt.Println(w.startTime) //0
|
||||
fmt.Println(w.stopTime) //0
|
||||
}
|
||||
|
||||
func longRunningTask() {
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
## 目录
|
||||
- [After](#After)
|
||||
- [Before](#Before)
|
||||
- [Curry](#Curry)
|
||||
- [CurryFn](#CurryFn)
|
||||
- [Compose](#Compose)
|
||||
- [Debounced](#Debounced)
|
||||
- [Delay](#Delay)
|
||||
@@ -124,15 +124,15 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <span id="Curry">Curry</span>
|
||||
### <span id="CurryFn">CurryFn</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>
|
||||
|
||||
@@ -148,11 +148,14 @@ 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))
|
||||
|
||||
var addCurry CurryFn[int] = func(values ...int) int {
|
||||
return add(values[0], values[1])
|
||||
}
|
||||
add1 := addCurry.Curry(1)
|
||||
add1 := addCurry.New(1)
|
||||
|
||||
result := add1(2)
|
||||
|
||||
fmt.Println(result) //3
|
||||
}
|
||||
```
|
||||
@@ -161,12 +164,12 @@ func main() {
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -179,17 +182,17 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
add1 := func(v ...any) any {
|
||||
return v[0].(int) + 1
|
||||
toUpper := func(strs ...string) string {
|
||||
return strings.ToUpper(strs[0])
|
||||
}
|
||||
add2 := func(v ...any) any {
|
||||
return v[0].(int) + 2
|
||||
toLower := func(strs ...string) string {
|
||||
return strings.ToLower(strs[0])
|
||||
}
|
||||
transform := Compose(toUpper, toLower)
|
||||
|
||||
add3 := function.Compose(add1, add2)
|
||||
result := add3(1)
|
||||
result := transform("aBCde")
|
||||
|
||||
fmt.Println(result) //4
|
||||
fmt.Println(result) //ABCDE
|
||||
}
|
||||
```
|
||||
|
||||
@@ -197,7 +200,7 @@ func main() {
|
||||
|
||||
### <span id="Debounced">Debounced</span>
|
||||
|
||||
<p>创建一个 debounced 函数,该函数延迟调用 fn 直到自上次调用 debounced 函数后等待持续时间过去。</p>
|
||||
<p>创建一个debounced函数,该函数延迟调用fn直到自上次调用debounced函数后等待持续时间过去。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -333,7 +336,7 @@ func main() {
|
||||
|
||||
f := Pipeline(addOne, double, square)
|
||||
|
||||
fmt.Println(f(2)) //36
|
||||
fmt.Println(fn(2)) //36
|
||||
}
|
||||
```
|
||||
|
||||
@@ -341,7 +344,7 @@ func main() {
|
||||
|
||||
### <span id="Watcher">Watcher</span>
|
||||
|
||||
<p>Watcher 用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。 </p>
|
||||
<p>Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -351,6 +354,7 @@ type Watcher struct {
|
||||
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
|
||||
@@ -367,7 +371,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
w := &function.Watcher{}
|
||||
w := function.NewWatcher()
|
||||
|
||||
w.Start()
|
||||
|
||||
longRunningTask()
|
||||
@@ -377,14 +382,11 @@ func main() {
|
||||
w.Stop()
|
||||
|
||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||
|
||||
fmt.Println(eapsedTime)
|
||||
|
||||
w.Reset()
|
||||
|
||||
fmt.Println(w.excuting) //false
|
||||
|
||||
fmt.Println(w.startTime) //0
|
||||
fmt.Println(w.stopTime) //0
|
||||
}
|
||||
|
||||
func longRunningTask() {
|
||||
|
||||
@@ -218,7 +218,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Min">Min</span>
|
||||
<p>Return min value of numbers.</p>
|
||||
<p>Return the minimum value of numbers.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -302,8 +302,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //0.5
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //0.33
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -299,8 +299,8 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
||||
fmt.Println(mathutil.Percent(1, 2, 2)) //0.5
|
||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //0.33
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -77,7 +78,7 @@ func main() {
|
||||
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -108,7 +109,7 @@ func main() {
|
||||
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -139,7 +140,7 @@ func main() {
|
||||
|
||||
|
||||
### <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>
|
||||
|
||||
@@ -631,9 +632,45 @@ func main() {
|
||||
|
||||
|
||||
|
||||
### <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)
|
||||
fmt.Println(result1) //bcd
|
||||
|
||||
result2 := strutil.Substring("abcde", 1, 5)
|
||||
fmt.Println(result2) //bcde
|
||||
|
||||
result3 := strutil.Substring("abcde", -1, 3)
|
||||
fmt.Println(result3) //e
|
||||
|
||||
result4 := strutil.Substring("abcde", -2, 2)
|
||||
fmt.Println(result4) //de
|
||||
|
||||
result5 := strutil.Substring("abcde", -2, 3)
|
||||
fmt.Println(result5) //de
|
||||
|
||||
result6 := strutil.Substring("你好,欢迎你", 0, 2)
|
||||
fmt.Println(result6) //你好
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="Wrap">Wrap</span>
|
||||
<p>Wrap a string with another string.</p>
|
||||
<p>Wrap a string with given string.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
@@ -670,7 +707,7 @@ func main() {
|
||||
|
||||
|
||||
### <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>
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
- [SnakeCase](#SnakeCase)
|
||||
- [UpperSnakeCase](#UpperSnakeCase)
|
||||
- [SplitEx](#SplitEx)
|
||||
- [Substring](#Substring)
|
||||
- [Wrap](#Wrap)
|
||||
- [Unwrap](#Unwrap)
|
||||
|
||||
@@ -48,7 +49,7 @@ import (
|
||||
|
||||
|
||||
### <span id="After">After</span>
|
||||
<p>截取源字符串中char首次出现时的位置之后的子字符串</p>
|
||||
<p>返回源字符串中特定字符串首次出现时的位置之后的子字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -78,7 +79,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="AfterLast">AfterLast</span>
|
||||
<p>截取源字符串中char最后一次出现时的位置之后的子字符串</p>
|
||||
<p>返回源字符串中指定字符串最后一次出现时的位置之后的子字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -109,7 +110,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="Before">Before</span>
|
||||
<p>截取源字符串中char首次出现时的位置之前的子字符串</p>
|
||||
<p>返回源字符串中指定字符串第一次出现时的位置之前的子字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -140,7 +141,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="BeforeLast">BeforeLast</span>
|
||||
<p>截取源字符串中char最后一次出现时的位置之前的子字符串</p>
|
||||
<p>返回源字符串中指定字符串最后一次出现时的位置之前的子字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -238,7 +239,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="IsString">IsString</span>
|
||||
<p>检查值的数据类型是否为字符串</p>
|
||||
<p>判断传入参数的数据类型是否为字符串</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -367,7 +368,7 @@ func main() {
|
||||
|
||||
|
||||
### <span id="UpperFirst">UpperFirst</span>
|
||||
<p>将字符串的第一个字符转换为大写</p>
|
||||
<p>将字符串的第一个字符转换为大写形式</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
@@ -600,6 +601,42 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <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)
|
||||
fmt.Println(result1) //bcd
|
||||
|
||||
result2 := strutil.Substring("abcde", 1, 5)
|
||||
fmt.Println(result2) //bcde
|
||||
|
||||
result3 := strutil.Substring("abcde", -1, 3)
|
||||
fmt.Println(result3) //e
|
||||
|
||||
result4 := strutil.Substring("abcde", -2, 2)
|
||||
fmt.Println(result4) //de
|
||||
|
||||
result5 := strutil.Substring("abcde", -2, 3)
|
||||
fmt.Println(result5) //de
|
||||
|
||||
result6 := strutil.Substring("你好,欢迎你", 0, 2)
|
||||
fmt.Println(result6) //你好
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### <span id="Wrap">Wrap</span>
|
||||
|
||||
@@ -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: Todo
|
||||
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: Todo
|
||||
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(1*time.Second, increase)
|
||||
|
||||
time.Sleep(3 * time.Second)
|
||||
close(stop)
|
||||
|
||||
fmt.Println(count)
|
||||
|
||||
// Output:
|
||||
// 3
|
||||
}
|
||||
|
||||
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: Todo
|
||||
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: Todo
|
||||
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))
|
||||
|
||||
|
||||
761
slice/slice_example_test.go
Normal file
761
slice/slice_example_test.go
Normal file
@@ -0,0 +1,761 @@
|
||||
package slice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func ExampleContain() {
|
||||
result1 := Contain([]string{"a", "b", "c"}, "a")
|
||||
result2 := Contain([]int{1, 2, 3}, 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleContainSubSlice() {
|
||||
result1 := ContainSubSlice([]string{"a", "b", "c"}, []string{"a", "b"})
|
||||
result2 := ContainSubSlice([]string{"a", "b", "c"}, []string{"a", "d"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleChunk() {
|
||||
arr := []string{"a", "b", "c", "d", "e"}
|
||||
|
||||
result1 := Chunk(arr, 1)
|
||||
result2 := Chunk(arr, 2)
|
||||
result3 := Chunk(arr, 3)
|
||||
result4 := Chunk(arr, 4)
|
||||
result5 := Chunk(arr, 5)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// [[a] [b] [c] [d] [e]]
|
||||
// [[a b] [c d] [e]]
|
||||
// [[a b c] [d e]]
|
||||
// [[a b c d] [e]]
|
||||
// [[a b c d e]]
|
||||
}
|
||||
|
||||
func ExampleCompact() {
|
||||
result1 := Compact([]int{0})
|
||||
result2 := Compact([]int{0, 1, 2, 3})
|
||||
result3 := Compact([]string{"", "a", "b", "0"})
|
||||
result4 := Compact([]bool{false, true, true})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// []
|
||||
// [1 2 3]
|
||||
// [a b 0]
|
||||
// [true true]
|
||||
}
|
||||
|
||||
func ExampleConcat() {
|
||||
result1 := Concat([]int{1, 2}, []int{3, 4})
|
||||
result2 := Concat([]string{"a", "b"}, []string{"c"}, []string{"d"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4]
|
||||
// [a b c d]
|
||||
}
|
||||
|
||||
func ExampleDifference() {
|
||||
slice1 := []int{1, 2, 3, 4, 5}
|
||||
slice2 := []int{4, 5, 6}
|
||||
|
||||
result := Difference(slice1, slice2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
|
||||
func ExampleDifferenceBy() {
|
||||
slice1 := []int{1, 2, 3, 4, 5} //after add one: 2 3 4 5 6
|
||||
slice2 := []int{3, 4, 5} //after add one: 4 5 6
|
||||
|
||||
addOne := func(i int, v int) int {
|
||||
return v + 1
|
||||
}
|
||||
|
||||
result := DifferenceBy(slice1, slice2, addOne)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 2]
|
||||
}
|
||||
|
||||
func ExampleDifferenceWith() {
|
||||
slice1 := []int{1, 2, 3, 4, 5}
|
||||
slice2 := []int{4, 5, 6, 7, 8}
|
||||
|
||||
isDouble := func(v1, v2 int) bool {
|
||||
return v2 == 2*v1
|
||||
}
|
||||
|
||||
result := DifferenceWith(slice1, slice2, isDouble)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 5]
|
||||
}
|
||||
|
||||
func ExampleEqual() {
|
||||
slice1 := []int{1, 2, 3}
|
||||
slice2 := []int{1, 2, 3}
|
||||
slice3 := []int{1, 3, 2}
|
||||
|
||||
result1 := Equal(slice1, slice2)
|
||||
result2 := Equal(slice1, slice3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleEqualWith() {
|
||||
slice1 := []int{1, 2, 3}
|
||||
slice2 := []int{2, 4, 6}
|
||||
|
||||
isDouble := func(a, b int) bool {
|
||||
return b == a*2
|
||||
}
|
||||
|
||||
result := EqualWith(slice1, slice2, isDouble)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleEvery() {
|
||||
nums := []int{1, 2, 3, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result := Every(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleNone() {
|
||||
nums := []int{1, 3, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result := None(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleSome() {
|
||||
nums := []int{1, 2, 3, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result := Some(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleFilter() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result := Filter(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [2 4]
|
||||
}
|
||||
|
||||
func ExampleCount() {
|
||||
nums := []int{1, 2, 3, 3, 4}
|
||||
|
||||
result1 := Count(nums, 1)
|
||||
result2 := Count(nums, 3)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleCountBy() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result := CountBy(nums, isEven)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
}
|
||||
|
||||
func ExampleGroupBy() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
even, odd := GroupBy(nums, isEven)
|
||||
|
||||
fmt.Println(even)
|
||||
fmt.Println(odd)
|
||||
|
||||
// Output:
|
||||
// [2 4]
|
||||
// [1 3 5]
|
||||
}
|
||||
|
||||
func ExampleGroupWith() {
|
||||
nums := []float64{6.1, 4.2, 6.3}
|
||||
|
||||
floor := func(num float64) float64 {
|
||||
return math.Floor(num)
|
||||
}
|
||||
|
||||
result := GroupWith(nums, floor) //map[float64][]float64
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[4:[4.2] 6:[6.1 6.3]]
|
||||
}
|
||||
|
||||
func ExampleFind() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result, ok := Find(nums, isEven)
|
||||
|
||||
fmt.Println(*result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 2
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleFindLast() {
|
||||
nums := []int{1, 2, 3, 4, 5}
|
||||
|
||||
isEven := func(i, num int) bool {
|
||||
return num%2 == 0
|
||||
}
|
||||
|
||||
result, ok := FindLast(nums, isEven)
|
||||
|
||||
fmt.Println(*result)
|
||||
fmt.Println(ok)
|
||||
|
||||
// Output:
|
||||
// 4
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleFlatten() {
|
||||
arrs := [][][]string{{{"a", "b"}}, {{"c", "d"}}}
|
||||
|
||||
result := Flatten(arrs)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [[a b] [c d]]
|
||||
}
|
||||
|
||||
func ExampleFlattenDeep() {
|
||||
arrs := [][][]string{{{"a", "b"}}, {{"c", "d"}}}
|
||||
|
||||
result := FlattenDeep(arrs)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [a b c d]
|
||||
}
|
||||
|
||||
func ExampleForEach() {
|
||||
nums := []int{1, 2, 3}
|
||||
|
||||
var result []int
|
||||
addOne := func(_ int, v int) {
|
||||
result = append(result, v+1)
|
||||
}
|
||||
|
||||
ForEach(nums, addOne)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [2 3 4]
|
||||
}
|
||||
|
||||
func ExampleMap() {
|
||||
nums := []int{1, 2, 3}
|
||||
|
||||
addOne := func(_ int, v int) int {
|
||||
return v + 1
|
||||
}
|
||||
|
||||
result := Map(nums, addOne)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [2 3 4]
|
||||
}
|
||||
|
||||
func ExampleReduce() {
|
||||
nums := []int{1, 2, 3}
|
||||
|
||||
sum := func(_ int, v1, v2 int) int {
|
||||
return v1 + v2
|
||||
}
|
||||
|
||||
result := Reduce(nums, sum, 0)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// 6
|
||||
}
|
||||
|
||||
func ExampleReplace() {
|
||||
strs := []string{"a", "b", "c", "a"}
|
||||
|
||||
result1 := Replace(strs, "a", "x", 0)
|
||||
result2 := Replace(strs, "a", "x", 1)
|
||||
result3 := Replace(strs, "a", "x", 2)
|
||||
result4 := Replace(strs, "a", "x", 3)
|
||||
result5 := Replace(strs, "a", "x", -1)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// [a b c a]
|
||||
// [x b c a]
|
||||
// [x b c x]
|
||||
// [x b c x]
|
||||
// [x b c x]
|
||||
}
|
||||
|
||||
func ExampleReplaceAll() {
|
||||
result := ReplaceAll([]string{"a", "b", "c", "a"}, "a", "x")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [x b c x]
|
||||
}
|
||||
|
||||
func ExampleRepeat() {
|
||||
result := Repeat("a", 3)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [a a a]
|
||||
}
|
||||
|
||||
func ExampleInterfaceSlice() {
|
||||
strs := []string{"a", "b", "c"}
|
||||
|
||||
result := InterfaceSlice(strs) //[]interface{}{"a", "b", "c"}
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
}
|
||||
|
||||
func ExampleStringSlice() {
|
||||
strs := []interface{}{"a", "b", "c"}
|
||||
|
||||
result := StringSlice(strs) //[]string{"a", "b", "c"}
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
}
|
||||
|
||||
func ExampleIntSlice() {
|
||||
nums := []interface{}{1, 2, 3}
|
||||
|
||||
result := IntSlice(nums) //[]int{1, 2, 3}
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 2 3]
|
||||
}
|
||||
|
||||
func ExampleDeleteAt() {
|
||||
result1 := DeleteAt([]string{"a", "b", "c"}, -1)
|
||||
result2 := DeleteAt([]string{"a", "b", "c"}, 0)
|
||||
result3 := DeleteAt([]string{"a", "b", "c"}, 0, 2)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [b c]
|
||||
// [c]
|
||||
}
|
||||
|
||||
func ExampleDrop() {
|
||||
result1 := Drop([]string{"a", "b", "c"}, 0)
|
||||
result2 := Drop([]string{"a", "b", "c"}, 1)
|
||||
result3 := Drop([]string{"a", "b", "c"}, -1)
|
||||
result4 := Drop([]string{"a", "b", "c"}, 4)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [b c]
|
||||
// [a b]
|
||||
// []
|
||||
}
|
||||
|
||||
func ExampleInsertAt() {
|
||||
result1 := InsertAt([]string{"a", "b", "c"}, 0, "1")
|
||||
result2 := InsertAt([]string{"a", "b", "c"}, 1, "1")
|
||||
result3 := InsertAt([]string{"a", "b", "c"}, 2, "1")
|
||||
result4 := InsertAt([]string{"a", "b", "c"}, 3, "1")
|
||||
result5 := InsertAt([]string{"a", "b", "c"}, 0, []string{"1", "2", "3"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// [1 a b c]
|
||||
// [a 1 b c]
|
||||
// [a b 1 c]
|
||||
// [a b c 1]
|
||||
// [1 2 3 a b c]
|
||||
}
|
||||
|
||||
func ExampleUpdateAt() {
|
||||
result1 := UpdateAt([]string{"a", "b", "c"}, -1, "1")
|
||||
result2 := UpdateAt([]string{"a", "b", "c"}, 0, "1")
|
||||
result3 := UpdateAt([]string{"a", "b", "c"}, 1, "1")
|
||||
result4 := UpdateAt([]string{"a", "b", "c"}, 2, "1")
|
||||
result5 := UpdateAt([]string{"a", "b", "c"}, 3, "1")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
// [1 b c]
|
||||
// [a 1 c]
|
||||
// [a b 1]
|
||||
// [a b c]
|
||||
}
|
||||
|
||||
func ExampleUnique() {
|
||||
result := Unique([]string{"a", "a", "b"})
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [a b]
|
||||
}
|
||||
|
||||
func ExampleUniqueBy() {
|
||||
nums := []int{1, 2, 3, 4, 5, 6}
|
||||
result := UniqueBy(nums, func(val int) int {
|
||||
return val % 3
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 2 0]
|
||||
}
|
||||
|
||||
func ExampleUnion() {
|
||||
nums1 := []int{1, 3, 4, 6}
|
||||
nums2 := []int{1, 2, 5, 6}
|
||||
|
||||
result := Union(nums1, nums2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 3 4 6 2 5]
|
||||
}
|
||||
|
||||
func ExampleUnionBy() {
|
||||
nums := []int{1, 2, 3, 4}
|
||||
|
||||
divideTwo := func(n int) int {
|
||||
return n / 2
|
||||
}
|
||||
result := UnionBy(divideTwo, nums)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 2 4]
|
||||
}
|
||||
|
||||
func ExampleMerge() {
|
||||
nums1 := []int{1, 2, 3}
|
||||
nums2 := []int{3, 4}
|
||||
|
||||
result := Merge(nums1, nums2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 3 4]
|
||||
}
|
||||
|
||||
func ExampleIntersection() {
|
||||
nums1 := []int{1, 2, 3}
|
||||
nums2 := []int{2, 3, 4}
|
||||
|
||||
result := Intersection(nums1, nums2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [2 3]
|
||||
}
|
||||
|
||||
func ExampleSymmetricDifference() {
|
||||
nums1 := []int{1, 2, 3}
|
||||
nums2 := []int{1, 2, 4}
|
||||
|
||||
result := SymmetricDifference(nums1, nums2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [3 4]
|
||||
}
|
||||
|
||||
func ExampleReverse() {
|
||||
strs := []string{"a", "b", "c", "d"}
|
||||
|
||||
Reverse(strs)
|
||||
|
||||
fmt.Println(strs)
|
||||
|
||||
// Output:
|
||||
// [d c b a]
|
||||
}
|
||||
|
||||
func ExampleSort() {
|
||||
nums := []int{1, 4, 3, 2, 5}
|
||||
|
||||
Sort(nums)
|
||||
|
||||
fmt.Println(nums)
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5]
|
||||
}
|
||||
|
||||
func ExampleSortBy() {
|
||||
type User struct {
|
||||
Name string
|
||||
Age uint
|
||||
}
|
||||
|
||||
users := []User{
|
||||
{Name: "a", Age: 21},
|
||||
{Name: "b", Age: 15},
|
||||
{Name: "c", Age: 100}}
|
||||
|
||||
SortBy(users, func(a, b User) bool {
|
||||
return a.Age < b.Age
|
||||
})
|
||||
|
||||
fmt.Println(users)
|
||||
|
||||
// Output:
|
||||
// [{b 15} {a 21} {c 100}]
|
||||
}
|
||||
|
||||
func ExampleSortByField() {
|
||||
type User struct {
|
||||
Name string
|
||||
Age uint
|
||||
}
|
||||
|
||||
users := []User{
|
||||
{Name: "a", Age: 21},
|
||||
{Name: "b", Age: 15},
|
||||
{Name: "c", Age: 100}}
|
||||
|
||||
err := SortByField(users, "Age", "desc")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(users)
|
||||
|
||||
// Output:
|
||||
// [{c 100} {a 21} {b 15}]
|
||||
}
|
||||
|
||||
func ExampleWithout() {
|
||||
result := Without([]int{1, 2, 3, 4}, 1, 2)
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [3 4]
|
||||
}
|
||||
|
||||
func ExampleIndexOf() {
|
||||
strs := []string{"a", "a", "b", "c"}
|
||||
|
||||
result1 := IndexOf(strs, "a")
|
||||
result2 := IndexOf(strs, "d")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 0
|
||||
// -1
|
||||
}
|
||||
|
||||
func ExampleLastIndexOf() {
|
||||
strs := []string{"a", "a", "b", "c"}
|
||||
|
||||
result1 := LastIndexOf(strs, "a")
|
||||
result2 := LastIndexOf(strs, "d")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// 1
|
||||
// -1
|
||||
}
|
||||
|
||||
func ExampleToSlice() {
|
||||
result := ToSlice("a", "b", "c")
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// [a b c]
|
||||
}
|
||||
|
||||
func ExampleToSlicePointer() {
|
||||
str1 := "a"
|
||||
str2 := "b"
|
||||
|
||||
result := ToSlicePointer(str1, str2)
|
||||
|
||||
expect := []*string{&str1, &str2}
|
||||
|
||||
isEqual := reflect.DeepEqual(result, expect)
|
||||
|
||||
fmt.Println(isEqual)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleAppendIfAbsent() {
|
||||
result1 := AppendIfAbsent([]string{"a", "b"}, "b")
|
||||
result2 := AppendIfAbsent([]string{"a", "b"}, "c")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
|
||||
// Output:
|
||||
// [a b]
|
||||
// [a b c]
|
||||
}
|
||||
|
||||
func ExampleKeyBy() {
|
||||
result := KeyBy([]string{"a", "ab", "abc"}, func(str string) int {
|
||||
return len(str)
|
||||
})
|
||||
|
||||
fmt.Println(result)
|
||||
|
||||
// Output:
|
||||
// map[1:a 2:ab 3:abc]
|
||||
}
|
||||
@@ -257,7 +257,7 @@ func TestFlatten(t *testing.T) {
|
||||
input := [][][]string{{{"a", "b"}}, {{"c", "d"}}}
|
||||
expected := [][]string{{"a", "b"}, {"c", "d"}}
|
||||
|
||||
assert := internal.NewAssert(t, "TestFlattenDeep")
|
||||
assert := internal.NewAssert(t, "TestFlatten")
|
||||
assert.Equal(expected, Flatten(input))
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,8 @@ import (
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// CamelCase covert string to camelCase string.
|
||||
// non letters and numbers will be ignored
|
||||
// eg. "Foo-#1😄$_%^&*(1bar" => "foo11Bar"
|
||||
// CamelCase coverts string to camelCase string. Non letters and numbers will be ignored.
|
||||
// Play: https://go.dev/play/p/9eXP3tn2tUy
|
||||
func CamelCase(s string) string {
|
||||
var builder strings.Builder
|
||||
|
||||
@@ -28,6 +27,7 @@ func CamelCase(s string) string {
|
||||
}
|
||||
|
||||
// Capitalize converts the first character of a string to upper case and the remaining to lower case.
|
||||
// Play: https://go.dev/play/p/2OAjgbmAqHZ
|
||||
func Capitalize(s string) string {
|
||||
result := make([]rune, len(s))
|
||||
for i, v := range s {
|
||||
@@ -42,6 +42,7 @@ func Capitalize(s string) string {
|
||||
}
|
||||
|
||||
// UpperFirst converts the first character of string to upper case.
|
||||
// Play: https://go.dev/play/p/sBbBxRbs8MM
|
||||
func UpperFirst(s string) string {
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
@@ -54,6 +55,7 @@ func UpperFirst(s string) string {
|
||||
}
|
||||
|
||||
// LowerFirst converts the first character of string to lower case.
|
||||
// Play: https://go.dev/play/p/CbzAyZmtJwL
|
||||
func LowerFirst(s string) string {
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
@@ -67,6 +69,7 @@ func LowerFirst(s string) string {
|
||||
|
||||
// PadEnd pads string on the right side if it's shorter than size.
|
||||
// Padding characters are truncated if they exceed size.
|
||||
// Play: https://go.dev/play/p/9xP8rN0vz--
|
||||
func PadEnd(source string, size int, padStr string) string {
|
||||
len1 := len(source)
|
||||
len2 := len(padStr)
|
||||
@@ -86,6 +89,7 @@ func PadEnd(source string, size int, padStr string) string {
|
||||
|
||||
// PadStart pads string on the left side if it's shorter than size.
|
||||
// Padding characters are truncated if they exceed size.
|
||||
// Play: https://go.dev/play/p/xpTfzArDfvT
|
||||
func PadStart(source string, size int, padStr string) string {
|
||||
len1 := len(source)
|
||||
len2 := len(padStr)
|
||||
@@ -103,39 +107,36 @@ func PadStart(source string, size int, padStr string) string {
|
||||
return fill[0:size-len1] + source
|
||||
}
|
||||
|
||||
// KebabCase covert string to kebab-case
|
||||
// non letters and numbers will be ignored
|
||||
// eg. "Foo-#1😄$_%^&*(1bar" => "foo-1-1-bar"
|
||||
// KebabCase coverts string to kebab-case, non letters and numbers will be ignored.
|
||||
// Play: https://go.dev/play/p/dcZM9Oahw-Y
|
||||
func KebabCase(s string) string {
|
||||
result := splitIntoStrings(s, false)
|
||||
return strings.Join(result, "-")
|
||||
}
|
||||
|
||||
// UpperKebabCase covert string to upper KEBAB-CASE
|
||||
// non letters and numbers will be ignored
|
||||
// eg. "Foo-#1😄$_%^&*(1bar" => "FOO-1-1-BAR"
|
||||
// UpperKebabCase coverts string to upper KEBAB-CASE, non letters and numbers will be ignored
|
||||
// Play: https://go.dev/play/p/zDyKNneyQXk
|
||||
func UpperKebabCase(s string) string {
|
||||
result := splitIntoStrings(s, true)
|
||||
return strings.Join(result, "-")
|
||||
}
|
||||
|
||||
// SnakeCase covert string to snake_case
|
||||
// non letters and numbers will be ignored
|
||||
// eg. "Foo-#1😄$_%^&*(1bar" => "foo_1_1_bar"
|
||||
// SnakeCase coverts string to snake_case, non letters and numbers will be ignored
|
||||
// Play: https://go.dev/play/p/tgzQG11qBuN
|
||||
func SnakeCase(s string) string {
|
||||
result := splitIntoStrings(s, false)
|
||||
return strings.Join(result, "_")
|
||||
}
|
||||
|
||||
// UpperSnakeCase covert string to upper SNAKE_CASE
|
||||
// non letters and numbers will be ignored
|
||||
// eg. "Foo-#1😄$_%^&*(1bar" => "FOO_1_1_BAR"
|
||||
// UpperSnakeCase coverts string to upper SNAKE_CASE, non letters and numbers will be ignored
|
||||
// Play: https://go.dev/play/p/4COPHpnLx38
|
||||
func UpperSnakeCase(s string) string {
|
||||
result := splitIntoStrings(s, true)
|
||||
return strings.Join(result, "_")
|
||||
}
|
||||
|
||||
// Before create substring in source string before position when char first appear
|
||||
// Before returns the substring of the source string up to the first occurrence of the specified string.
|
||||
// Play: https://go.dev/play/p/JAWTZDS4F5w
|
||||
func Before(s, char string) string {
|
||||
if s == "" || char == "" {
|
||||
return s
|
||||
@@ -144,7 +145,8 @@ func Before(s, char string) string {
|
||||
return s[0:i]
|
||||
}
|
||||
|
||||
// BeforeLast create substring in source string before position when char last appear
|
||||
// BeforeLast returns the substring of the source string up to the last occurrence of the specified string.
|
||||
// Play: https://go.dev/play/p/pJfXXAoG_Te
|
||||
func BeforeLast(s, char string) string {
|
||||
if s == "" || char == "" {
|
||||
return s
|
||||
@@ -153,7 +155,8 @@ func BeforeLast(s, char string) string {
|
||||
return s[0:i]
|
||||
}
|
||||
|
||||
// After create substring in source string after position when char first appear
|
||||
// After returns the substring after the first occurrence of a specified string in the source string.
|
||||
// Play: https://go.dev/play/p/RbCOQqCDA7m
|
||||
func After(s, char string) string {
|
||||
if s == "" || char == "" {
|
||||
return s
|
||||
@@ -162,7 +165,8 @@ func After(s, char string) string {
|
||||
return s[i+len(char):]
|
||||
}
|
||||
|
||||
// AfterLast create substring in source string after position when char last appear
|
||||
// AfterLast returns the substring after the last occurrence of a specified string in the source string.
|
||||
// Play: https://go.dev/play/p/1TegARrb8Yn
|
||||
func AfterLast(s, char string) string {
|
||||
if s == "" || char == "" {
|
||||
return s
|
||||
@@ -172,6 +176,7 @@ func AfterLast(s, char string) string {
|
||||
}
|
||||
|
||||
// IsString check if the value data type is string or not.
|
||||
// Play: https://go.dev/play/p/IOgq7oF9ERm
|
||||
func IsString(v any) bool {
|
||||
if v == nil {
|
||||
return false
|
||||
@@ -184,7 +189,8 @@ func IsString(v any) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Reverse return string whose char order is reversed to the given string
|
||||
// Reverse returns string whose char order is reversed to the given string.
|
||||
// Play: https://go.dev/play/p/adfwalJiecD
|
||||
func Reverse(s string) string {
|
||||
r := []rune(s)
|
||||
for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
|
||||
@@ -193,7 +199,8 @@ func Reverse(s string) string {
|
||||
return string(r)
|
||||
}
|
||||
|
||||
// Wrap a string with another string.
|
||||
// Wrap a string with given string.
|
||||
// Play: https://go.dev/play/p/KoZOlZDDt9y
|
||||
func Wrap(str string, wrapWith string) string {
|
||||
if str == "" || wrapWith == "" {
|
||||
return str
|
||||
@@ -206,7 +213,8 @@ func Wrap(str string, wrapWith string) string {
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// Unwrap a given string from anther string. will change str value
|
||||
// Unwrap a given string from anther string. will change source string.
|
||||
// Play: https://go.dev/play/p/Ec2q4BzCpG-
|
||||
func Unwrap(str string, wrapToken string) string {
|
||||
if str == "" || wrapToken == "" {
|
||||
return str
|
||||
@@ -224,7 +232,8 @@ func Unwrap(str string, wrapToken string) string {
|
||||
return str
|
||||
}
|
||||
|
||||
// SplitEx split a given string whether the result contains empty string
|
||||
// SplitEx split a given string which can control the result slice contains empty string or not.
|
||||
// Play: https://go.dev/play/p/Us-ySSbWh-3
|
||||
func SplitEx(s, sep string, removeEmptyString bool) []string {
|
||||
if sep == "" {
|
||||
return []string{}
|
||||
@@ -272,3 +281,28 @@ func SplitEx(s, sep string, removeEmptyString bool) []string {
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// Substring returns a substring of the specified length starting at the specified offset position.
|
||||
// Play: Todo
|
||||
func Substring(s string, offset int, length uint) string {
|
||||
rs := []rune(s)
|
||||
size := len(rs)
|
||||
|
||||
if offset < 0 {
|
||||
offset = size + offset
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
}
|
||||
if offset > size {
|
||||
return ""
|
||||
}
|
||||
|
||||
if length > uint(size)-uint(offset) {
|
||||
length = uint(size - offset)
|
||||
}
|
||||
|
||||
str := string(rs[offset : offset+int(length)])
|
||||
|
||||
return strings.Replace(str, "\x00", "", -1)
|
||||
}
|
||||
|
||||
363
strutil/string_example_test.go
Normal file
363
strutil/string_example_test.go
Normal file
@@ -0,0 +1,363 @@
|
||||
package strutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func ExampleAfter() {
|
||||
result1 := After("foo", "")
|
||||
result2 := After("foo", "foo")
|
||||
result3 := After("foo/bar", "foo")
|
||||
result4 := After("foo/bar", "/")
|
||||
result5 := After("foo/bar/baz", "/")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
// Output:
|
||||
// foo
|
||||
//
|
||||
// /bar
|
||||
// bar
|
||||
// bar/baz
|
||||
}
|
||||
|
||||
func ExampleAfterLast() {
|
||||
result1 := AfterLast("foo", "")
|
||||
result2 := AfterLast("foo", "foo")
|
||||
result3 := AfterLast("foo/bar", "/")
|
||||
result4 := AfterLast("foo/bar/baz", "/")
|
||||
result5 := AfterLast("foo/bar/foo/baz", "foo")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
// Output:
|
||||
// foo
|
||||
//
|
||||
// bar
|
||||
// baz
|
||||
// /baz
|
||||
}
|
||||
|
||||
func ExampleBefore() {
|
||||
result1 := Before("foo", "")
|
||||
result2 := Before("foo", "foo")
|
||||
result3 := Before("foo/bar", "/")
|
||||
result4 := Before("foo/bar/baz", "/")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
// Output:
|
||||
// foo
|
||||
//
|
||||
// foo
|
||||
// foo
|
||||
}
|
||||
|
||||
func ExampleBeforeLast() {
|
||||
result1 := BeforeLast("foo", "")
|
||||
result2 := BeforeLast("foo", "foo")
|
||||
result3 := BeforeLast("foo/bar", "/")
|
||||
result4 := BeforeLast("foo/bar/baz", "/")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
// Output:
|
||||
// foo
|
||||
//
|
||||
// foo
|
||||
// foo/bar
|
||||
}
|
||||
|
||||
func ExampleCamelCase() {
|
||||
strings := []string{"", "foobar", "&FOO:BAR$BAZ", "$foo%", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
for _, v := range strings {
|
||||
s := CamelCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
// Output:
|
||||
//
|
||||
// foobar
|
||||
// fooBarBaz
|
||||
// foo
|
||||
// foo11Bar
|
||||
}
|
||||
|
||||
func ExampleCapitalize() {
|
||||
strings := []string{"", "Foo", "_foo", "fooBar", "foo-bar"}
|
||||
|
||||
for _, v := range strings {
|
||||
s := Capitalize(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
// Output:
|
||||
//
|
||||
// Foo
|
||||
// _foo
|
||||
// Foobar
|
||||
// Foo-bar
|
||||
}
|
||||
|
||||
func ExampleIsString() {
|
||||
result1 := IsString("")
|
||||
result2 := IsString("a")
|
||||
result3 := IsString(1)
|
||||
result4 := IsString(true)
|
||||
result5 := IsString([]string{"a"})
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleKebabCase() {
|
||||
strings := []string{"", "foo-bar", "Foo Bar-", "FOOBAR", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
for _, v := range strings {
|
||||
s := KebabCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
// Output:
|
||||
//
|
||||
// foo-bar
|
||||
// foo-bar
|
||||
// foobar
|
||||
// foo-1-1-bar
|
||||
}
|
||||
|
||||
func ExampleUpperKebabCase() {
|
||||
strings := []string{"", "foo-bar", "Foo Bar-", "FooBAR", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
for _, v := range strings {
|
||||
s := UpperKebabCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
// Output:
|
||||
//
|
||||
// FOO-BAR
|
||||
// FOO-BAR
|
||||
// FOO-BAR
|
||||
// FOO-1-1-BAR
|
||||
}
|
||||
|
||||
func ExampleLowerFirst() {
|
||||
strings := []string{"", "bar", "BAr", "Bar大"}
|
||||
|
||||
for _, v := range strings {
|
||||
s := LowerFirst(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
// Output:
|
||||
//
|
||||
// bar
|
||||
// bAr
|
||||
// bar大
|
||||
}
|
||||
|
||||
func ExampleUpperFirst() {
|
||||
strings := []string{"", "bar", "BAr", "bar大"}
|
||||
|
||||
for _, v := range strings {
|
||||
s := UpperFirst(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
// Output:
|
||||
//
|
||||
// Bar
|
||||
// BAr
|
||||
// Bar大
|
||||
}
|
||||
|
||||
func ExamplePadEnd() {
|
||||
result1 := PadEnd("foo", 1, "bar")
|
||||
result2 := PadEnd("foo", 2, "bar")
|
||||
result3 := PadEnd("foo", 3, "bar")
|
||||
result4 := PadEnd("foo", 4, "bar")
|
||||
result5 := PadEnd("foo", 5, "bar")
|
||||
result6 := PadEnd("foo", 6, "bar")
|
||||
result7 := PadEnd("foo", 7, "bar")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
// Output:
|
||||
// foo
|
||||
// foo
|
||||
// foo
|
||||
// foob
|
||||
// fooba
|
||||
// foobar
|
||||
// foobarb
|
||||
}
|
||||
|
||||
func ExamplePadStart() {
|
||||
result1 := PadStart("foo", 1, "bar")
|
||||
result2 := PadStart("foo", 2, "bar")
|
||||
result3 := PadStart("foo", 3, "bar")
|
||||
result4 := PadStart("foo", 4, "bar")
|
||||
result5 := PadStart("foo", 5, "bar")
|
||||
result6 := PadStart("foo", 6, "bar")
|
||||
result7 := PadStart("foo", 7, "bar")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
fmt.Println(result6)
|
||||
fmt.Println(result7)
|
||||
// Output:
|
||||
// foo
|
||||
// foo
|
||||
// foo
|
||||
// bfoo
|
||||
// bafoo
|
||||
// barfoo
|
||||
// barbfoo
|
||||
}
|
||||
|
||||
func ExampleReverse() {
|
||||
s := "foo"
|
||||
rs := Reverse(s)
|
||||
|
||||
fmt.Println(s)
|
||||
fmt.Println(rs)
|
||||
// Output:
|
||||
// foo
|
||||
// oof
|
||||
}
|
||||
|
||||
func ExampleSnakeCase() {
|
||||
strings := []string{"", "foo-bar", "Foo Bar-", "FOOBAR", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
for _, v := range strings {
|
||||
s := SnakeCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
// Output:
|
||||
//
|
||||
// foo_bar
|
||||
// foo_bar
|
||||
// foobar
|
||||
// foo_1_1_bar
|
||||
}
|
||||
|
||||
func ExampleUpperSnakeCase() {
|
||||
strings := []string{"", "foo-bar", "Foo Bar-", "FooBAR", "Foo-#1😄$_%^&*(1bar"}
|
||||
|
||||
for _, v := range strings {
|
||||
s := UpperSnakeCase(v)
|
||||
fmt.Println(s)
|
||||
}
|
||||
// Output:
|
||||
//
|
||||
// FOO_BAR
|
||||
// FOO_BAR
|
||||
// FOO_BAR
|
||||
// FOO_1_1_BAR
|
||||
}
|
||||
|
||||
func ExampleSplitEx() {
|
||||
result1 := SplitEx(" a b c ", "", true)
|
||||
|
||||
result2 := SplitEx(" a b c ", " ", false)
|
||||
result3 := SplitEx(" a b c ", " ", true)
|
||||
|
||||
result4 := SplitEx("a = b = c = ", " = ", false)
|
||||
result5 := SplitEx("a = b = c = ", " = ", true)
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
// Output:
|
||||
// []
|
||||
// [ a b c ]
|
||||
// [a b c]
|
||||
// [a b c ]
|
||||
// [a b c]
|
||||
}
|
||||
|
||||
func ExampleWrap() {
|
||||
result1 := Wrap("foo", "")
|
||||
result2 := Wrap("foo", "*")
|
||||
result3 := Wrap("'foo'", "'")
|
||||
result4 := Wrap("", "*")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
// Output:
|
||||
// foo
|
||||
// *foo*
|
||||
// ''foo''
|
||||
//
|
||||
}
|
||||
|
||||
func ExampleUnwrap() {
|
||||
result1 := Unwrap("foo", "")
|
||||
result2 := Unwrap("*foo*", "*")
|
||||
result3 := Unwrap("*foo", "*")
|
||||
result4 := Unwrap("foo*", "*")
|
||||
result5 := Unwrap("**foo**", "*")
|
||||
|
||||
fmt.Println(result1)
|
||||
fmt.Println(result2)
|
||||
fmt.Println(result3)
|
||||
fmt.Println(result4)
|
||||
fmt.Println(result5)
|
||||
// Output:
|
||||
// foo
|
||||
// foo
|
||||
// *foo
|
||||
// foo*
|
||||
// *foo*
|
||||
}
|
||||
|
||||
func ExampleSubstring() {
|
||||
|
||||
result1 := Substring("abcde", 1, 3)
|
||||
result2 := Substring("abcde", 1, 5)
|
||||
result3 := Substring("abcde", -1, 3)
|
||||
result4 := Substring("abcde", -2, 2)
|
||||
result5 := Substring("abcde", -2, 3)
|
||||
result6 := 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
|
||||
// 你好
|
||||
}
|
||||
@@ -196,6 +196,7 @@ func TestBefore(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestBefore")
|
||||
|
||||
assert.Equal("lancet", Before("lancet", ""))
|
||||
assert.Equal("", Before("lancet", "lancet"))
|
||||
assert.Equal("github.com", Before("github.com/test/lancet", "/"))
|
||||
assert.Equal("github.com/", Before("github.com/test/lancet", "test"))
|
||||
}
|
||||
@@ -214,6 +215,7 @@ func TestAfter(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestAfter")
|
||||
|
||||
assert.Equal("lancet", After("lancet", ""))
|
||||
assert.Equal("", After("lancet", "lancet"))
|
||||
assert.Equal("test/lancet", After("github.com/test/lancet", "/"))
|
||||
assert.Equal("/lancet", After("github.com/test/lancet", "test"))
|
||||
}
|
||||
@@ -282,6 +284,17 @@ func TestSplitEx(t *testing.T) {
|
||||
assert.Equal([]string{"", "a", "b", "c", ""}, SplitEx(" a b c ", " ", false))
|
||||
assert.Equal([]string{"a", "b", "c"}, SplitEx(" a b c ", " ", true))
|
||||
|
||||
assert.Equal([]string{" a", "b", "c", ""}, SplitEx(" a = b = c = ", " = ", false))
|
||||
assert.Equal([]string{" a", "b", "c"}, SplitEx(" a = b = c = ", " = ", true))
|
||||
assert.Equal([]string{"a", "b", "c", ""}, SplitEx("a = b = c = ", " = ", false))
|
||||
assert.Equal([]string{"a", "b", "c"}, SplitEx("a = b = c = ", " = ", true))
|
||||
}
|
||||
|
||||
func TestSubstring(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestSubstring")
|
||||
|
||||
assert.Equal("bcd", Substring("abcde", 1, 3))
|
||||
assert.Equal("bcde", Substring("abcde", 1, 5))
|
||||
assert.Equal("e", Substring("abcde", -1, 3))
|
||||
assert.Equal("de", Substring("abcde", -2, 2))
|
||||
assert.Equal("de", Substring("abcde", -2, 3))
|
||||
assert.Equal("你好", Substring("你好,欢迎你", 0, 2))
|
||||
}
|
||||
|
||||
20
system/os.go
20
system/os.go
@@ -15,37 +15,44 @@ import (
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
)
|
||||
|
||||
// IsWindows check if current os is windows
|
||||
// IsWindows check if current os is windows.
|
||||
// Play: https://go.dev/play/p/XzJULbzmf9m
|
||||
func IsWindows() bool {
|
||||
return runtime.GOOS == "windows"
|
||||
}
|
||||
|
||||
// IsLinux check if current os is linux
|
||||
// IsLinux check if current os is linux.
|
||||
// Play: https://go.dev/play/p/zIflQgZNuxD
|
||||
func IsLinux() bool {
|
||||
return runtime.GOOS == "linux"
|
||||
}
|
||||
|
||||
// IsMac check if current os is macos
|
||||
// IsMac check if current os is macos.
|
||||
// Play: https://go.dev/play/p/Mg4Hjtyq7Zc
|
||||
func IsMac() bool {
|
||||
return runtime.GOOS == "darwin"
|
||||
}
|
||||
|
||||
// GetOsEnv gets the value of the environment variable named by the key.
|
||||
// Play: https://go.dev/play/p/D88OYVCyjO-
|
||||
func GetOsEnv(key string) string {
|
||||
return os.Getenv(key)
|
||||
}
|
||||
|
||||
// SetOsEnv sets the value of the environment variable named by the key.
|
||||
// Play: https://go.dev/play/p/D88OYVCyjO-
|
||||
func SetOsEnv(key, value string) error {
|
||||
return os.Setenv(key, value)
|
||||
}
|
||||
|
||||
// RemoveOsEnv remove a single environment variable.
|
||||
// Play: https://go.dev/play/p/fqyq4b3xUFQ
|
||||
func RemoveOsEnv(key string) error {
|
||||
return os.Unsetenv(key)
|
||||
}
|
||||
|
||||
// CompareOsEnv gets env named by the key and compare it with comparedEnv
|
||||
// CompareOsEnv gets env named by the key and compare it with comparedEnv.
|
||||
// Play: https://go.dev/play/p/BciHrKYOHbp
|
||||
func CompareOsEnv(key, comparedEnv string) bool {
|
||||
env := GetOsEnv(key)
|
||||
if env == "" {
|
||||
@@ -58,6 +65,7 @@ func CompareOsEnv(key, comparedEnv string) bool {
|
||||
// param `command` is a complete command string, like, ls -a (linux), dir(windows), ping 127.0.0.1
|
||||
// in linux, use /bin/bash -c to execute command
|
||||
// in windows, use powershell.exe to execute command
|
||||
// Play: https://go.dev/play/p/n-2fLyZef-4
|
||||
func ExecCommand(command string) (stdout, stderr string, err error) {
|
||||
var out bytes.Buffer
|
||||
var errOut bytes.Buffer
|
||||
@@ -109,8 +117,8 @@ func byteToString(data []byte, charset string) string {
|
||||
return result
|
||||
}
|
||||
|
||||
// GetOsBits get this system bits 32bit or 64bit
|
||||
// return bit int (32/64)
|
||||
// GetOsBits return current os bits (32 or 64).
|
||||
// Play: https://go.dev/play/p/ml-_XH3gJbW
|
||||
func GetOsBits() int {
|
||||
return 32 << (^uint(0) >> 63)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user