mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-21 21:02:27 +08:00
Compare commits
93 Commits
2d905ab03e
...
v2.1.13
| 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 | ||
|
|
b7e5d946f1 | ||
|
|
687db4ce79 | ||
|
|
a9a4bb8841 | ||
|
|
bc6cb5f61b | ||
|
|
2c57266f8e | ||
|
|
57e49c9520 | ||
|
|
985c9a5d9a | ||
|
|
5cfb11f036 | ||
|
|
5b3d48a1e7 | ||
|
|
d0576e028f | ||
|
|
76bdec2b54 | ||
|
|
fa20aba3a7 | ||
|
|
7a4a429e23 | ||
|
|
a70ec6ad1e | ||
|
|
e435fa271b | ||
|
|
1533d00891 | ||
|
|
8b99641de0 | ||
|
|
251f899f18 | ||
|
|
00407e5182 | ||
|
|
4e457ad672 | ||
|
|
7d8d9c3543 | ||
|
|
1197e8d1b6 | ||
|
|
13bbe19ab2 | ||
|
|
2725575d2f | ||
|
|
037d2729ce | ||
|
|
09d98745b0 | ||
|
|
af5cfe6da1 | ||
|
|
d59259bbe0 | ||
|
|
3189628d54 | ||
|
|
62c5e251a5 | ||
|
|
6e6444c8c0 | ||
|
|
dd613e98b2 |
1229
README_zh-CN.md
1229
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
|
length int
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLRUCache return a LRUCache pointer
|
// NewLRUCache creates a LRUCache pointer instance.
|
||||||
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
|
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
|
||||||
return &LRUCache[K, V]{
|
return &LRUCache[K, V]{
|
||||||
cache: make(map[K]*lruNode[K, V], capacity),
|
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) {
|
func (l *LRUCache[K, V]) Get(key K) (V, bool) {
|
||||||
var value V
|
var value V
|
||||||
|
|
||||||
@@ -50,7 +51,8 @@ func (l *LRUCache[K, V]) Get(key K) (V, bool) {
|
|||||||
return value, false
|
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) {
|
func (l *LRUCache[K, V]) Put(key K, value V) {
|
||||||
node, ok := l.cache[key]
|
node, ok := l.cache[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -69,6 +71,23 @@ func (l *LRUCache[K, V]) Put(key K, value V) {
|
|||||||
l.length = len(l.cache)
|
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]) {
|
func (l *LRUCache[K, V]) addNode(node *lruNode[K, V]) {
|
||||||
if l.tail != nil {
|
if l.tail != nil {
|
||||||
l.tail.next = node
|
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) {
|
func TestLRUCache(t *testing.T) {
|
||||||
asssert := internal.NewAssert(t, "TestLRUCache")
|
asssert := internal.NewAssert(t, "TestLRUCache")
|
||||||
|
|
||||||
cache := NewLRUCache[int, int](2)
|
cache := NewLRUCache[int, int](3)
|
||||||
|
|
||||||
cache.Put(1, 1)
|
cache.Put(1, 1)
|
||||||
cache.Put(2, 2)
|
cache.Put(2, 2)
|
||||||
|
cache.Put(3, 3)
|
||||||
|
|
||||||
_, ok := cache.Get(0)
|
asssert.Equal(3, cache.Len())
|
||||||
asssert.Equal(false, ok)
|
|
||||||
|
|
||||||
v, ok := cache.Get(1)
|
v, ok := cache.Get(1)
|
||||||
asssert.Equal(true, ok)
|
asssert.Equal(true, ok)
|
||||||
@@ -25,12 +25,9 @@ func TestLRUCache(t *testing.T) {
|
|||||||
asssert.Equal(true, ok)
|
asssert.Equal(true, ok)
|
||||||
asssert.Equal(2, v)
|
asssert.Equal(2, v)
|
||||||
|
|
||||||
cache.Put(3, 3)
|
ok = cache.Delete(2)
|
||||||
v, ok = cache.Get(1)
|
|
||||||
asssert.Equal(false, ok)
|
|
||||||
asssert.NotEqual(1, v)
|
|
||||||
|
|
||||||
v, ok = cache.Get(3)
|
|
||||||
asssert.Equal(true, ok)
|
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.
|
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||||
// Use of this source code is governed by MIT license
|
// 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
|
package algorithm
|
||||||
|
|
||||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||||
|
|
||||||
// Search algorithms see https://github.com/TheAlgorithms/Go/tree/master/search
|
// Search algorithms see https://github.com/TheAlgorithms/Go/tree/master/search
|
||||||
|
|
||||||
// LinearSearch Simple linear search algorithm that iterates over all elements of an slice
|
// LinearSearch return the index of target in slice base on equal function.
|
||||||
// If a target is found, the index of the target is returned. Else the function return -1
|
// If not found return -1
|
||||||
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int {
|
// Play: Todo
|
||||||
|
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int {
|
||||||
for i, v := range slice {
|
for i, v := range slice {
|
||||||
if comparator.Compare(v, target) == 0 {
|
if equal(v, target) {
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// BinarySearch search for target within a sorted slice, recursive call itself.
|
// BinarySearch return the index of target within a sorted slice, use binary search (recursive call itself).
|
||||||
// If a target is found, the index of the target is returned. Else the function return -1
|
// 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 {
|
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||||
if highIndex < lowIndex || len(sortedSlice) == 0 {
|
if highIndex < lowIndex || len(sortedSlice) == 0 {
|
||||||
return -1
|
return -1
|
||||||
@@ -39,8 +41,9 @@ func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, com
|
|||||||
return midIndex
|
return midIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
// BinaryIterativeSearch search for target within a sorted slice.
|
// BinaryIterativeSearch return the index of target within a sorted slice, use binary search (no recursive).
|
||||||
// If a target is found, the index of the target is returned. Else the function return -1
|
// 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 {
|
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
|
||||||
startIndex := lowIndex
|
startIndex := lowIndex
|
||||||
endIndex := highIndex
|
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"
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
|
|
||||||
|
|
||||||
func TestLinearSearch(t *testing.T) {
|
func TestLinearSearch(t *testing.T) {
|
||||||
asssert := internal.NewAssert(t, "TestLinearSearch")
|
asssert := internal.NewAssert(t, "TestLinearSearch")
|
||||||
|
|
||||||
comparator := &intComparator{}
|
numbers := []int{3, 4, 5, 3, 2, 1}
|
||||||
asssert.Equal(4, LinearSearch(sortedNumbers, 5, comparator))
|
equalFunc := func(a, b int) bool {
|
||||||
asssert.Equal(-1, LinearSearch(sortedNumbers, 9, comparator))
|
return a == b
|
||||||
|
}
|
||||||
|
|
||||||
|
asssert.Equal(0, LinearSearch(numbers, 3, equalFunc))
|
||||||
|
asssert.Equal(-1, LinearSearch(numbers, 6, equalFunc))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBinarySearch(t *testing.T) {
|
func TestBinarySearch(t *testing.T) {
|
||||||
asssert := internal.NewAssert(t, "TestBinarySearch")
|
asssert := internal.NewAssert(t, "TestBinarySearch")
|
||||||
|
|
||||||
|
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||||
comparator := &intComparator{}
|
comparator := &intComparator{}
|
||||||
|
|
||||||
asssert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
asssert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||||
asssert.Equal(-1, BinarySearch(sortedNumbers, 9, 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) {
|
func TestBinaryIterativeSearch(t *testing.T) {
|
||||||
asssert := internal.NewAssert(t, "TestBinaryIterativeSearch")
|
asssert := internal.NewAssert(t, "TestBinaryIterativeSearch")
|
||||||
|
|
||||||
|
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
|
||||||
comparator := &intComparator{}
|
comparator := &intComparator{}
|
||||||
|
|
||||||
asssert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
asssert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
|
||||||
asssert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 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.
|
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
|
||||||
// Use of this source code is governed by MIT license
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
// Package algorithm contain some basic algorithm functions. eg. sort, search
|
|
||||||
package algorithm
|
package algorithm
|
||||||
|
|
||||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
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) {
|
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||||
for i := 0; i < len(slice); i++ {
|
for i := 0; i < len(slice); i++ {
|
||||||
for j := 0; j < len(slice)-1-i; j++ {
|
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) {
|
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||||
for i := 0; i < len(slice); i++ {
|
for i := 0; i < len(slice); i++ {
|
||||||
for j := i; j > 0; j-- {
|
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) {
|
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||||
for i := 0; i < len(slice); i++ {
|
for i := 0; i < len(slice); i++ {
|
||||||
min := 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) {
|
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||||
size := len(slice)
|
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) {
|
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||||
quickSort(slice, 0, len(slice)-1, 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
|
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) {
|
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||||
size := len(slice)
|
size := len(slice)
|
||||||
|
|
||||||
@@ -126,7 +131,8 @@ func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraint
|
|||||||
slice[i] = temp
|
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) {
|
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator) {
|
||||||
mergeSort(slice, 0, len(slice)-1, 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 {
|
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T {
|
||||||
size := len(slice)
|
size := len(slice)
|
||||||
out := make([]T, size)
|
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) {
|
func TestBubbleSortForIntSlice(t *testing.T) {
|
||||||
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
|
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
|
||||||
|
|
||||||
numbers := []int{2, 1, 5, 3, 6, 4}
|
numbers := []int{2, 1, 5, 3, 6, 4}
|
||||||
comparator := &intComparator{}
|
comparator := &intComparator{}
|
||||||
BubbleSort(numbers, comparator)
|
BubbleSort(numbers, comparator)
|
||||||
|
|||||||
@@ -11,17 +11,18 @@ import (
|
|||||||
|
|
||||||
// Channel is a logic object which can generate or manipulate go channel
|
// Channel is a logic object which can generate or manipulate go channel
|
||||||
// all methods of Channel are in the book tilted《Concurrency in Go》
|
// 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
|
// NewChannel return a Channel instance
|
||||||
func NewChannel() *Channel {
|
func NewChannel[T any]() *Channel[T] {
|
||||||
return &Channel{}
|
return &Channel[T]{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a data of type any chan, put param `values` into the chan
|
// Generate creates channel, then put values into the channel.
|
||||||
func (c *Channel) Generate(ctx context.Context, values ...any) <-chan any {
|
// Play: Todo
|
||||||
dataStream := make(chan any)
|
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T {
|
||||||
|
dataStream := make(chan T)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(dataStream)
|
defer close(dataStream)
|
||||||
@@ -38,9 +39,10 @@ func (c *Channel) Generate(ctx context.Context, values ...any) <-chan any {
|
|||||||
return dataStream
|
return dataStream
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repeat return a data of type any chan, put param `values` into the chan repeatly until cancel the context.
|
// Repeat create channel, put values into the channel repeatly until cancel the context.
|
||||||
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any {
|
// Play: Todo
|
||||||
dataStream := make(chan any)
|
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T {
|
||||||
|
dataStream := make(chan T)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(dataStream)
|
defer close(dataStream)
|
||||||
@@ -57,10 +59,11 @@ func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any {
|
|||||||
return dataStream
|
return dataStream
|
||||||
}
|
}
|
||||||
|
|
||||||
// RepeatFn return a chan, excutes fn repeatly, and put the result into retruned chan
|
// RepeatFn create a channel, excutes fn repeatly, and put the result into the channel
|
||||||
// until close the `done` channel
|
// until close context.
|
||||||
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any {
|
// Play: Todo
|
||||||
dataStream := make(chan any)
|
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T {
|
||||||
|
dataStream := make(chan T)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(dataStream)
|
defer close(dataStream)
|
||||||
@@ -75,9 +78,10 @@ func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any {
|
|||||||
return dataStream
|
return dataStream
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take return a chan whose values are tahken from another chan
|
// Take create a channel whose values are taken from another channel with limit number.
|
||||||
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any {
|
// Play: Todo
|
||||||
takeStream := make(chan any)
|
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T {
|
||||||
|
takeStream := make(chan T)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(takeStream)
|
defer close(takeStream)
|
||||||
@@ -94,16 +98,17 @@ func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int)
|
|||||||
return takeStream
|
return takeStream
|
||||||
}
|
}
|
||||||
|
|
||||||
// FanIn merge multiple channels into one channel
|
// FanIn merge multiple channels into one channel.
|
||||||
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any {
|
// Play: Todo
|
||||||
out := make(chan any)
|
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T {
|
||||||
|
out := make(chan T)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(len(channels))
|
wg.Add(len(channels))
|
||||||
|
|
||||||
for _, c := range channels {
|
for _, c := range channels {
|
||||||
go func(c <-chan any) {
|
go func(c <-chan T) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
for v := range c {
|
for v := range c {
|
||||||
select {
|
select {
|
||||||
@@ -121,10 +126,11 @@ func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tee split one chanel into two channels
|
// Tee split one chanel into two channels, until cancel the context.
|
||||||
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any) {
|
// Play: Todo
|
||||||
out1 := make(chan any)
|
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T) {
|
||||||
out2 := make(chan any)
|
out1 := make(chan T)
|
||||||
|
out2 := make(chan T)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(out1)
|
defer close(out1)
|
||||||
@@ -147,18 +153,19 @@ func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan an
|
|||||||
return out1, out2
|
return out1, out2
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bridge link multiply channels into one channel
|
// Bridge link multiply channels into one channel.
|
||||||
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any {
|
// Play: Todo
|
||||||
valStream := make(chan any)
|
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T {
|
||||||
|
valStream := make(chan T)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(valStream)
|
defer close(valStream)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var stream <-chan any
|
var stream <-chan T
|
||||||
select {
|
select {
|
||||||
case maybeStream, ok := <-chanStream:
|
case maybeStream, ok := <-chanStream:
|
||||||
if ok == false {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
stream = maybeStream
|
stream = maybeStream
|
||||||
@@ -178,8 +185,9 @@ func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-ch
|
|||||||
return valStream
|
return valStream
|
||||||
}
|
}
|
||||||
|
|
||||||
// Or read one or more channels into one channel, will close when any readin channel is closed
|
// 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 {
|
// Play: Todo
|
||||||
|
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T {
|
||||||
switch len(channels) {
|
switch len(channels) {
|
||||||
case 0:
|
case 0:
|
||||||
return nil
|
return nil
|
||||||
@@ -187,7 +195,7 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
|
|||||||
return channels[0]
|
return channels[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
orDone := make(chan any)
|
orDone := make(chan T)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(orDone)
|
defer close(orDone)
|
||||||
@@ -199,17 +207,12 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
|
|||||||
case <-channels[1]:
|
case <-channels[1]:
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
m := len(channels) / 2
|
|
||||||
select {
|
select {
|
||||||
case <-c.Or(channels[:m]...):
|
case <-channels[0]:
|
||||||
case <-c.Or(channels[m:]...):
|
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.
|
// OrDone read a channel into another channel, will close until cancel context.
|
||||||
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any {
|
// Play: Todo
|
||||||
valStream := make(chan any)
|
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T {
|
||||||
|
valStream := make(chan T)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(valStream)
|
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())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := NewChannel()
|
c := NewChannel[int]()
|
||||||
intStream := c.Generate(ctx, 1, 2, 3)
|
intStream := c.Generate(ctx, 1, 2, 3)
|
||||||
|
|
||||||
// for v := range intStream {
|
|
||||||
// t.Log(v) //1, 2, 3
|
|
||||||
// }
|
|
||||||
assert.Equal(1, <-intStream)
|
assert.Equal(1, <-intStream)
|
||||||
assert.Equal(2, <-intStream)
|
assert.Equal(2, <-intStream)
|
||||||
assert.Equal(3, <-intStream)
|
assert.Equal(3, <-intStream)
|
||||||
@@ -31,12 +28,9 @@ func TestRepeat(t *testing.T) {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := NewChannel()
|
c := NewChannel[int]()
|
||||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
|
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(1, <-intStream)
|
||||||
assert.Equal(2, <-intStream)
|
assert.Equal(2, <-intStream)
|
||||||
assert.Equal(1, <-intStream)
|
assert.Equal(1, <-intStream)
|
||||||
@@ -50,17 +44,13 @@ func TestRepeatFn(t *testing.T) {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
fn := func() any {
|
fn := func() string {
|
||||||
s := "a"
|
s := "a"
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
c := NewChannel()
|
c := NewChannel[string]()
|
||||||
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
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)
|
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())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
numbers := make(chan any, 5)
|
numbers := make(chan int, 5)
|
||||||
numbers <- 1
|
numbers <- 1
|
||||||
numbers <- 2
|
numbers <- 2
|
||||||
numbers <- 3
|
numbers <- 3
|
||||||
@@ -80,7 +70,7 @@ func TestTake(t *testing.T) {
|
|||||||
numbers <- 5
|
numbers <- 5
|
||||||
defer close(numbers)
|
defer close(numbers)
|
||||||
|
|
||||||
c := NewChannel()
|
c := NewChannel[int]()
|
||||||
intStream := c.Take(ctx, numbers, 3)
|
intStream := c.Take(ctx, numbers, 3)
|
||||||
|
|
||||||
assert.Equal(1, <-intStream)
|
assert.Equal(1, <-intStream)
|
||||||
@@ -94,8 +84,8 @@ func TestFanIn(t *testing.T) {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := NewChannel()
|
c := NewChannel[int]()
|
||||||
channels := make([]<-chan any, 3)
|
channels := make([]<-chan int, 3)
|
||||||
|
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
||||||
@@ -124,7 +114,7 @@ func TestOr(t *testing.T) {
|
|||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
c := NewChannel()
|
c := NewChannel[any]()
|
||||||
<-c.Or(
|
<-c.Or(
|
||||||
sig(1*time.Second),
|
sig(1*time.Second),
|
||||||
sig(2*time.Second),
|
sig(2*time.Second),
|
||||||
@@ -133,9 +123,7 @@ func TestOr(t *testing.T) {
|
|||||||
sig(5*time.Second),
|
sig(5*time.Second),
|
||||||
)
|
)
|
||||||
|
|
||||||
t.Logf("done after %v", time.Since(start))
|
assert.Equal(true, time.Since(start).Seconds() < 2)
|
||||||
|
|
||||||
assert.Equal(1, 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOrDone(t *testing.T) {
|
func TestOrDone(t *testing.T) {
|
||||||
@@ -144,16 +132,12 @@ func TestOrDone(t *testing.T) {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := NewChannel()
|
c := NewChannel[int]()
|
||||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||||
|
|
||||||
var res any
|
|
||||||
for val := range c.OrDone(ctx, intStream) {
|
for val := range c.OrDone(ctx, intStream) {
|
||||||
t.Logf("%v", val)
|
assert.Equal(1, val)
|
||||||
res = val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(1, res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTee(t *testing.T) {
|
func TestTee(t *testing.T) {
|
||||||
@@ -162,15 +146,13 @@ func TestTee(t *testing.T) {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := NewChannel()
|
c := NewChannel[int]()
|
||||||
inStream := c.Take(ctx, c.Repeat(ctx, 1), 4)
|
inStream := c.Take(ctx, c.Repeat(ctx, 1), 4)
|
||||||
|
|
||||||
out1, out2 := c.Tee(ctx, inStream)
|
out1, out2 := c.Tee(ctx, inStream)
|
||||||
for val := range out1 {
|
for val := range out1 {
|
||||||
val1 := val
|
val1 := val
|
||||||
val2 := <-out2
|
val2 := <-out2
|
||||||
// t.Log("val1 is", val1)
|
|
||||||
// t.Log("val2 is", val2)
|
|
||||||
assert.Equal(1, val1)
|
assert.Equal(1, val1)
|
||||||
assert.Equal(1, val2)
|
assert.Equal(1, val2)
|
||||||
}
|
}
|
||||||
@@ -182,13 +164,13 @@ func TestBridge(t *testing.T) {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := NewChannel()
|
c := NewChannel[int]()
|
||||||
genVals := func() <-chan <-chan any {
|
genVals := func() <-chan <-chan int {
|
||||||
chanStream := make(chan (<-chan any))
|
chanStream := make(chan (<-chan int))
|
||||||
go func() {
|
go func() {
|
||||||
defer close(chanStream)
|
defer close(chanStream)
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
stream := make(chan any, 1)
|
stream := make(chan int, 1)
|
||||||
stream <- i
|
stream <- i
|
||||||
close(stream)
|
close(stream)
|
||||||
chanStream <- stream
|
chanStream <- stream
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import "reflect"
|
|||||||
// If the type has an IsZero() bool method, the opposite value is returned.
|
// 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.
|
// 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.
|
// 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 {
|
func Bool[T any](value T) bool {
|
||||||
switch m := any(value).(type) {
|
switch m := any(value).(type) {
|
||||||
case interface{ Bool() bool }:
|
case interface{ Bool() bool }:
|
||||||
@@ -34,40 +35,47 @@ func reflectValue(vp any) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// And returns true if both a and b are truthy.
|
// 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 {
|
func And[T, U any](a T, b U) bool {
|
||||||
return Bool(a) && Bool(b)
|
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 {
|
func Or[T, U any](a T, b U) bool {
|
||||||
return Bool(a) || Bool(b)
|
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 {
|
func Xor[T, U any](a T, b U) bool {
|
||||||
valA := Bool(a)
|
valA := Bool(a)
|
||||||
valB := Bool(b)
|
valB := Bool(b)
|
||||||
return (valA || valB) && valA != valB
|
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 {
|
func Nor[T, U any](a T, b U) bool {
|
||||||
return !(Bool(a) || Bool(b))
|
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 {
|
func Xnor[T, U any](a T, b U) bool {
|
||||||
valA := Bool(a)
|
valA := Bool(a)
|
||||||
valB := Bool(b)
|
valB := Bool(b)
|
||||||
return (valA && valB) || (!valA && !valB)
|
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 {
|
func Nand[T, U any](a T, b U) bool {
|
||||||
return !Bool(a) || !Bool(b)
|
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 {
|
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
|
||||||
if Bool(isTrue) {
|
if Bool(isTrue) {
|
||||||
return ifValue
|
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"
|
"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) {
|
func ToBool(s string) (bool, error) {
|
||||||
return strconv.ParseBool(s)
|
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) {
|
func ToBytes(value any) ([]byte, error) {
|
||||||
v := reflect.ValueOf(value)
|
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 {
|
func ToChar(s string) []string {
|
||||||
c := make([]string, 0)
|
c := make([]string, 0)
|
||||||
if len(s) == 0 {
|
if len(s) == 0 {
|
||||||
@@ -75,7 +78,8 @@ func ToChar(s string) []string {
|
|||||||
return c
|
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 {
|
func ToChannel[T any](array []T) <-chan T {
|
||||||
ch := make(chan T)
|
ch := make(chan T)
|
||||||
|
|
||||||
@@ -91,44 +95,48 @@ func ToChannel[T any](array []T) <-chan T {
|
|||||||
|
|
||||||
// ToString convert value to string
|
// ToString convert value to string
|
||||||
// for number, string, []byte, will convert 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 {
|
func ToString(value any) string {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
switch value.(type) {
|
switch val := value.(type) {
|
||||||
case float32:
|
case float32:
|
||||||
return strconv.FormatFloat(float64(value.(float32)), 'f', -1, 32)
|
return strconv.FormatFloat(float64(val), 'f', -1, 32)
|
||||||
case float64:
|
case float64:
|
||||||
return strconv.FormatFloat(value.(float64), 'f', -1, 64)
|
return strconv.FormatFloat(val, 'f', -1, 64)
|
||||||
case int:
|
case int:
|
||||||
return strconv.FormatInt(int64(value.(int)), 10)
|
return strconv.FormatInt(int64(val), 10)
|
||||||
case int8:
|
case int8:
|
||||||
return strconv.FormatInt(int64(value.(int8)), 10)
|
return strconv.FormatInt(int64(val), 10)
|
||||||
case int16:
|
case int16:
|
||||||
return strconv.FormatInt(int64(value.(int16)), 10)
|
return strconv.FormatInt(int64(val), 10)
|
||||||
case int32:
|
case int32:
|
||||||
return strconv.FormatInt(int64(value.(int32)), 10)
|
return strconv.FormatInt(int64(val), 10)
|
||||||
case int64:
|
case int64:
|
||||||
return strconv.FormatInt(value.(int64), 10)
|
return strconv.FormatInt(val, 10)
|
||||||
case uint:
|
case uint:
|
||||||
return strconv.FormatUint(uint64(value.(uint)), 10)
|
return strconv.FormatUint(uint64(val), 10)
|
||||||
case uint8:
|
case uint8:
|
||||||
return strconv.FormatUint(uint64(value.(uint8)), 10)
|
return strconv.FormatUint(uint64(val), 10)
|
||||||
case uint16:
|
case uint16:
|
||||||
return strconv.FormatUint(uint64(value.(uint16)), 10)
|
return strconv.FormatUint(uint64(val), 10)
|
||||||
case uint32:
|
case uint32:
|
||||||
return strconv.FormatUint(uint64(value.(uint32)), 10)
|
return strconv.FormatUint(uint64(val), 10)
|
||||||
case uint64:
|
case uint64:
|
||||||
return strconv.FormatUint(value.(uint64), 10)
|
return strconv.FormatUint(val, 10)
|
||||||
case string:
|
case string:
|
||||||
return value.(string)
|
return val
|
||||||
case []byte:
|
case []byte:
|
||||||
return string(value.([]byte))
|
return string(val)
|
||||||
default:
|
default:
|
||||||
newValue, _ := json.Marshal(value)
|
b, err := json.Marshal(val)
|
||||||
return string(newValue)
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
|
||||||
// todo: maybe we should't supprt other type conversion
|
// todo: maybe we should't supprt other type conversion
|
||||||
// v := reflect.ValueOf(value)
|
// v := reflect.ValueOf(value)
|
||||||
@@ -137,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) {
|
func ToJson(value any) (string, error) {
|
||||||
result, err := json.Marshal(value)
|
result, err := json.Marshal(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -147,7 +156,8 @@ func ToJson(value any) (string, error) {
|
|||||||
return string(result), nil
|
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) {
|
func ToFloat(value any) (float64, error) {
|
||||||
v := reflect.ValueOf(value)
|
v := reflect.ValueOf(value)
|
||||||
|
|
||||||
@@ -174,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) {
|
func ToInt(value any) (int64, error) {
|
||||||
v := reflect.ValueOf(value)
|
v := reflect.ValueOf(value)
|
||||||
|
|
||||||
var result int64
|
var result int64
|
||||||
err := fmt.Errorf("ToInt: invalid interface type %T", value)
|
err := fmt.Errorf("ToInt: invalid value type %T", value)
|
||||||
switch value.(type) {
|
switch value.(type) {
|
||||||
case int, int8, int16, int32, int64:
|
case int, int8, int16, int32, int64:
|
||||||
result = v.Int()
|
result = v.Int()
|
||||||
@@ -201,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 {
|
func ToPointer[T any](value T) *T {
|
||||||
return &value
|
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 {
|
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))
|
result := make(map[K]V, len(array))
|
||||||
for _, item := range array {
|
for _, item := range array {
|
||||||
@@ -218,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
|
// 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) {
|
func StructToMap(value any) (map[string]any, error) {
|
||||||
v := reflect.ValueOf(value)
|
v := reflect.ValueOf(value)
|
||||||
t := reflect.TypeOf(value)
|
t := reflect.TypeOf(value)
|
||||||
@@ -247,7 +261,8 @@ func StructToMap(value any) (map[string]any, error) {
|
|||||||
return result, nil
|
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 {
|
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T {
|
||||||
result := make([]T, 0, len(aMap))
|
result := make([]T, 0, len(aMap))
|
||||||
|
|
||||||
@@ -258,7 +273,8 @@ func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T)
|
|||||||
return result
|
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) {
|
func ColorHexToRGB(colorHex string) (red, green, blue int) {
|
||||||
colorHex = strings.TrimPrefix(colorHex, "#")
|
colorHex = strings.TrimPrefix(colorHex, "#")
|
||||||
color64, err := strconv.ParseInt(colorHex, 16, 32)
|
color64, err := strconv.ParseInt(colorHex, 16, 32)
|
||||||
@@ -269,7 +285,8 @@ func ColorHexToRGB(colorHex string) (red, green, blue int) {
|
|||||||
return color >> 16, (color & 0x00FF00) >> 8, color & 0x0000FF
|
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 {
|
func ColorRGBToHex(red, green, blue int) string {
|
||||||
r := strconv.FormatInt(int64(red), 16)
|
r := strconv.FormatInt(int64(red), 16)
|
||||||
g := strconv.FormatInt(int64(green), 16)
|
g := strconv.FormatInt(int64(green), 16)
|
||||||
@@ -288,7 +305,8 @@ func ColorRGBToHex(red, green, blue int) string {
|
|||||||
return "#" + r + g + b
|
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) {
|
func EncodeByte(data any) ([]byte, error) {
|
||||||
buffer := bytes.NewBuffer(nil)
|
buffer := bytes.NewBuffer(nil)
|
||||||
encoder := gob.NewEncoder(buffer)
|
encoder := gob.NewEncoder(buffer)
|
||||||
@@ -299,7 +317,8 @@ func EncodeByte(data any) ([]byte, error) {
|
|||||||
return buffer.Bytes(), nil
|
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 {
|
func DecodeByte(data []byte, target any) error {
|
||||||
buffer := bytes.NewBuffer(data)
|
buffer := bytes.NewBuffer(data)
|
||||||
decoder := gob.NewDecoder(buffer)
|
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
|
||||||
|
}
|
||||||
@@ -27,14 +27,9 @@ func TestToChannel(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestToChannel")
|
assert := internal.NewAssert(t, "TestToChannel")
|
||||||
|
|
||||||
ch := ToChannel([]int{1, 2, 3})
|
ch := ToChannel([]int{1, 2, 3})
|
||||||
val1, _ := <-ch
|
assert.Equal(1, <-ch)
|
||||||
assert.Equal(1, val1)
|
assert.Equal(2, <-ch)
|
||||||
|
assert.Equal(3, <-ch)
|
||||||
val2, _ := <-ch
|
|
||||||
assert.Equal(2, val2)
|
|
||||||
|
|
||||||
val3, _ := <-ch
|
|
||||||
assert.Equal(3, val3)
|
|
||||||
|
|
||||||
_, ok := <-ch
|
_, ok := <-ch
|
||||||
assert.Equal(false, ok)
|
assert.Equal(false, ok)
|
||||||
@@ -254,6 +249,7 @@ func TestDecodeByte(t *testing.T) {
|
|||||||
|
|
||||||
var obj string
|
var obj string
|
||||||
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
|
||||||
DecodeByte(byteData, &obj)
|
err := DecodeByte(byteData, &obj)
|
||||||
|
assert.IsNil(err)
|
||||||
assert.Equal("abc", obj)
|
assert.Equal("abc", obj)
|
||||||
}
|
}
|
||||||
|
|||||||
174
cryptor/aes.go
174
cryptor/aes.go
@@ -1,174 +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 {
|
|
||||||
cipher, _ := aes.NewCipher(generateAesKey(key))
|
|
||||||
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))
|
|
||||||
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 {
|
|
||||||
block, _ := aes.NewCipher(key)
|
|
||||||
if len(encrypted) < aes.BlockSize {
|
|
||||||
panic("encrypted data is too short")
|
|
||||||
}
|
|
||||||
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"
|
"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 {
|
func Base64StdEncode(s string) string {
|
||||||
return base64.StdEncoding.EncodeToString([]byte(s))
|
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 {
|
func Base64StdDecode(s string) string {
|
||||||
b, _ := base64.StdEncoding.DecodeString(s)
|
b, _ := base64.StdEncoding.DecodeString(s)
|
||||||
return string(b)
|
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 {
|
func Md5String(s string) string {
|
||||||
h := md5.New()
|
h := md5.New()
|
||||||
h.Write([]byte(s))
|
h.Write([]byte(s))
|
||||||
return hex.EncodeToString(h.Sum(nil))
|
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) {
|
func Md5File(filename string) (string, error) {
|
||||||
if fileInfo, err := os.Stat(filename); err != nil {
|
if fileInfo, err := os.Stat(filename); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
@@ -69,49 +72,56 @@ func Md5File(filename string) (string, error) {
|
|||||||
return checksum, nil
|
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 {
|
func HmacMd5(data, key string) string {
|
||||||
h := hmac.New(md5.New, []byte(key))
|
h := hmac.New(md5.New, []byte(key))
|
||||||
h.Write([]byte(data))
|
h.Write([]byte(data))
|
||||||
return hex.EncodeToString(h.Sum([]byte("")))
|
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 {
|
func HmacSha1(data, key string) string {
|
||||||
h := hmac.New(sha1.New, []byte(key))
|
h := hmac.New(sha1.New, []byte(key))
|
||||||
h.Write([]byte(data))
|
h.Write([]byte(data))
|
||||||
return hex.EncodeToString(h.Sum([]byte("")))
|
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 {
|
func HmacSha256(data, key string) string {
|
||||||
h := hmac.New(sha256.New, []byte(key))
|
h := hmac.New(sha256.New, []byte(key))
|
||||||
h.Write([]byte(data))
|
h.Write([]byte(data))
|
||||||
return hex.EncodeToString(h.Sum([]byte("")))
|
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 {
|
func HmacSha512(data, key string) string {
|
||||||
h := hmac.New(sha512.New, []byte(key))
|
h := hmac.New(sha512.New, []byte(key))
|
||||||
h.Write([]byte(data))
|
h.Write([]byte(data))
|
||||||
return hex.EncodeToString(h.Sum([]byte("")))
|
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 {
|
func Sha1(data string) string {
|
||||||
sha1 := sha1.New()
|
sha1 := sha1.New()
|
||||||
sha1.Write([]byte(data))
|
sha1.Write([]byte(data))
|
||||||
return hex.EncodeToString(sha1.Sum([]byte("")))
|
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 {
|
func Sha256(data string) string {
|
||||||
sha256 := sha256.New()
|
sha256 := sha256.New()
|
||||||
sha256.Write([]byte(data))
|
sha256.Write([]byte(data))
|
||||||
return hex.EncodeToString(sha256.Sum([]byte("")))
|
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 {
|
func Sha512(data string) string {
|
||||||
sha512 := sha512.New()
|
sha512 := sha512.New()
|
||||||
sha512.Write([]byte(data))
|
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
|
||||||
|
}
|
||||||
178
cryptor/des.go
178
cryptor/des.go
@@ -1,178 +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 {
|
|
||||||
cipher, _ := des.NewCipher(generateDesKey(key))
|
|
||||||
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))
|
|
||||||
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))
|
||||||
|
}
|
||||||
118
cryptor/rsa.go
118
cryptor/rsa.go
@@ -1,118 +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)
|
|
||||||
}
|
|
||||||
pem.Encode(file, &block)
|
|
||||||
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("rsa_public.pem")
|
|
||||||
file, err = os.Create(pubKeyFile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
pem.Encode(file, &block)
|
|
||||||
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())
|
|
||||||
file.Read(buf)
|
|
||||||
|
|
||||||
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()
|
|
||||||
file.Read(buf)
|
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
@@ -146,9 +146,9 @@ func (h *MaxHeap[T]) PrintStructure() {
|
|||||||
lastNum := powerTwo(level - 1)
|
lastNum := powerTwo(level - 1)
|
||||||
lastLen := lastNum + (lastNum - 1)
|
lastLen := lastNum + (lastNum - 1)
|
||||||
|
|
||||||
heapTree := make([][]string, level, level)
|
heapTree := make([][]string, level)
|
||||||
for i := 0; i < level; i++ {
|
for i := 0; i < level; i++ {
|
||||||
heapTree[i] = make([]string, lastLen, lastLen)
|
heapTree[i] = make([]string, lastLen)
|
||||||
for j := 0; j < lastLen; j++ {
|
for j := 0; j < lastLen; j++ {
|
||||||
heapTree[i][j] = ""
|
heapTree[i][j] = ""
|
||||||
}
|
}
|
||||||
@@ -169,9 +169,9 @@ func (h *MaxHeap[T]) PrintStructure() {
|
|||||||
for n := 0; n < lastLen; n++ {
|
for n := 0; n < lastLen; n++ {
|
||||||
val := heapTree[m][n]
|
val := heapTree[m][n]
|
||||||
if val == "" {
|
if val == "" {
|
||||||
fmt.Printf(" ")
|
fmt.Print(" ")
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf(val)
|
fmt.Print(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ func TestMaxHeap_BuildMaxHeap(t *testing.T) {
|
|||||||
assert.Equal(expected, heap.data)
|
assert.Equal(expected, heap.data)
|
||||||
|
|
||||||
assert.Equal(12, heap.Size())
|
assert.Equal(12, heap.Size())
|
||||||
|
|
||||||
heap.PrintStructure()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMaxHeap_Push(t *testing.T) {
|
func TestMaxHeap_Push(t *testing.T) {
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
package datastructure
|
package datastructure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/datastructure"
|
"github.com/duke-git/lancet/v2/datastructure"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DoublyLink is a linked list. Whose node has a generic Value, Pre pointer points to a previous node of the link, Next pointer points to a next node of the link.
|
// DoublyLink is a linked list. Whose node has a generic Value, Pre pointer points to a previous node of the dl, Next pointer points to a next node of the dl.
|
||||||
type DoublyLink[T any] struct {
|
type DoublyLink[T any] struct {
|
||||||
Head *datastructure.LinkNode[T]
|
Head *datastructure.LinkNode[T]
|
||||||
length int
|
length int
|
||||||
@@ -19,30 +18,30 @@ func NewDoublyLink[T any]() *DoublyLink[T] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InsertAtHead insert value into doubly linklist at head index
|
// InsertAtHead insert value into doubly linklist at head index
|
||||||
func (link *DoublyLink[T]) InsertAtHead(value T) {
|
func (dl *DoublyLink[T]) InsertAtHead(value T) {
|
||||||
newNode := datastructure.NewLinkNode(value)
|
newNode := datastructure.NewLinkNode(value)
|
||||||
size := link.Size()
|
size := dl.Size()
|
||||||
|
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
link.Head = newNode
|
dl.Head = newNode
|
||||||
link.length++
|
dl.length++
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
newNode.Next = link.Head
|
newNode.Next = dl.Head
|
||||||
newNode.Pre = nil
|
newNode.Pre = nil
|
||||||
|
|
||||||
link.Head.Pre = newNode
|
dl.Head.Pre = newNode
|
||||||
link.Head = newNode
|
dl.Head = newNode
|
||||||
|
|
||||||
link.length++
|
dl.length++
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertAtTail insert value into doubly linklist at tail index
|
// InsertAtTail insert value into doubly linklist at tail index
|
||||||
func (link *DoublyLink[T]) InsertAtTail(value T) {
|
func (dl *DoublyLink[T]) InsertAtTail(value T) {
|
||||||
current := link.Head
|
current := dl.Head
|
||||||
if current == nil {
|
if current == nil {
|
||||||
link.InsertAtHead(value)
|
dl.InsertAtHead(value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,28 +54,29 @@ func (link *DoublyLink[T]) InsertAtTail(value T) {
|
|||||||
newNode.Pre = current
|
newNode.Pre = current
|
||||||
current.Next = newNode
|
current.Next = newNode
|
||||||
|
|
||||||
link.length++
|
dl.length++
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertAt insert value into doubly linklist at index
|
// InsertAt insert value into doubly linklist at index
|
||||||
func (link *DoublyLink[T]) InsertAt(index int, value T) error {
|
// param `index` should between [0, length], if index do not meet the conditions, do nothing
|
||||||
size := link.length
|
func (dl *DoublyLink[T]) InsertAt(index int, value T) {
|
||||||
|
size := dl.length
|
||||||
if index < 0 || index > size {
|
if index < 0 || index > size {
|
||||||
return errors.New("param index should between 0 and the length of doubly link.")
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
link.InsertAtHead(value)
|
dl.InsertAtHead(value)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == size {
|
if index == size {
|
||||||
link.InsertAtTail(value)
|
dl.InsertAtTail(value)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
current := link.Head
|
current := dl.Head
|
||||||
|
|
||||||
for current != nil {
|
for current != nil {
|
||||||
if i == index-1 {
|
if i == index-1 {
|
||||||
@@ -85,38 +85,36 @@ func (link *DoublyLink[T]) InsertAt(index int, value T) error {
|
|||||||
newNode.Pre = current
|
newNode.Pre = current
|
||||||
|
|
||||||
current.Next = newNode
|
current.Next = newNode
|
||||||
link.length++
|
dl.length++
|
||||||
|
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
current = current.Next
|
current = current.Next
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New("doubly link list no exist")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAtHead delete value in doubly linklist at head index
|
// DeleteAtHead delete value in doubly linklist at head index
|
||||||
func (link *DoublyLink[T]) DeleteAtHead() error {
|
func (dl *DoublyLink[T]) DeleteAtHead() {
|
||||||
if link.Head == nil {
|
if dl.Head == nil {
|
||||||
return errors.New("doubly link list no exist")
|
return
|
||||||
}
|
}
|
||||||
current := link.Head
|
|
||||||
link.Head = current.Next
|
|
||||||
link.Head.Pre = nil
|
|
||||||
link.length--
|
|
||||||
|
|
||||||
return nil
|
current := dl.Head
|
||||||
|
dl.Head = current.Next
|
||||||
|
dl.Head.Pre = nil
|
||||||
|
dl.length--
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAtTail delete value in doubly linklist at tail index
|
// DeleteAtTail delete value in doubly linklist at tail
|
||||||
func (link *DoublyLink[T]) DeleteAtTail() error {
|
func (dl *DoublyLink[T]) DeleteAtTail() {
|
||||||
if link.Head == nil {
|
if dl.Head == nil {
|
||||||
return errors.New("doubly link list no exist")
|
return
|
||||||
}
|
}
|
||||||
current := link.Head
|
|
||||||
|
current := dl.Head
|
||||||
if current.Next == nil {
|
if current.Next == nil {
|
||||||
return link.DeleteAtHead()
|
dl.DeleteAtHead()
|
||||||
}
|
}
|
||||||
|
|
||||||
for current.Next.Next != nil {
|
for current.Next.Next != nil {
|
||||||
@@ -124,45 +122,44 @@ func (link *DoublyLink[T]) DeleteAtTail() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
current.Next = nil
|
current.Next = nil
|
||||||
link.length--
|
dl.length--
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAt delete value in doubly linklist at index
|
// DeleteAt delete value in doubly linklist at index
|
||||||
func (link *DoublyLink[T]) DeleteAt(index int) error {
|
// param `index` should be [0, len(DoublyLink)-1]
|
||||||
if link.Head == nil {
|
func (dl *DoublyLink[T]) DeleteAt(index int) {
|
||||||
return errors.New("doubly link list no exist")
|
if dl.Head == nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
current := link.Head
|
|
||||||
|
current := dl.Head
|
||||||
if current.Next == nil || index == 0 {
|
if current.Next == nil || index == 0 {
|
||||||
return link.DeleteAtHead()
|
dl.DeleteAtHead()
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == link.length-1 {
|
if index == dl.length-1 {
|
||||||
return link.DeleteAtTail()
|
dl.DeleteAtTail()
|
||||||
}
|
}
|
||||||
|
|
||||||
if index < 0 || index > link.length-1 {
|
if index < 0 || index > dl.length-1 {
|
||||||
return errors.New("param index should between 0 and link size -1.")
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
for current != nil {
|
for current != nil {
|
||||||
if i == index-1 {
|
if i == index-1 {
|
||||||
current.Next = current.Next.Next
|
current.Next = current.Next.Next
|
||||||
link.length--
|
dl.length--
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
current = current.Next
|
current = current.Next
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New("delete error")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse the linked list
|
// Reverse the linked list
|
||||||
func (link *DoublyLink[T]) Reverse() {
|
func (dl *DoublyLink[T]) Reverse() {
|
||||||
current := link.Head
|
current := dl.Head
|
||||||
var temp *datastructure.LinkNode[T]
|
var temp *datastructure.LinkNode[T]
|
||||||
|
|
||||||
for current != nil {
|
for current != nil {
|
||||||
@@ -173,20 +170,20 @@ func (link *DoublyLink[T]) Reverse() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if temp != nil {
|
if temp != nil {
|
||||||
link.Head = temp.Pre
|
dl.Head = temp.Pre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMiddleNode return node at middle index of linked list
|
// GetMiddleNode return node at middle index of linked list
|
||||||
func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
func (dl *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||||
if link.Head == nil {
|
if dl.Head == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if link.Head.Next == nil {
|
if dl.Head.Next == nil {
|
||||||
return link.Head
|
return dl.Head
|
||||||
}
|
}
|
||||||
fast := link.Head
|
fast := dl.Head
|
||||||
slow := link.Head
|
slow := dl.Head
|
||||||
|
|
||||||
for fast != nil {
|
for fast != nil {
|
||||||
fast = fast.Next
|
fast = fast.Next
|
||||||
@@ -202,14 +199,14 @@ func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Size return the count of doubly linked list
|
// Size return the count of doubly linked list
|
||||||
func (link *DoublyLink[T]) Size() int {
|
func (dl *DoublyLink[T]) Size() int {
|
||||||
return link.length
|
return dl.length
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values return slice of all doubly linklist node value
|
// Values return slice of all doubly linklist node value
|
||||||
func (link *DoublyLink[T]) Values() []T {
|
func (dl *DoublyLink[T]) Values() []T {
|
||||||
result := []T{}
|
result := []T{}
|
||||||
current := link.Head
|
current := dl.Head
|
||||||
for current != nil {
|
for current != nil {
|
||||||
result = append(result, current.Value)
|
result = append(result, current.Value)
|
||||||
current = current.Next
|
current = current.Next
|
||||||
@@ -218,8 +215,8 @@ func (link *DoublyLink[T]) Values() []T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Print all nodes info of a linked list
|
// Print all nodes info of a linked list
|
||||||
func (link *DoublyLink[T]) Print() {
|
func (dl *DoublyLink[T]) Print() {
|
||||||
current := link.Head
|
current := dl.Head
|
||||||
info := "[ "
|
info := "[ "
|
||||||
for current != nil {
|
for current != nil {
|
||||||
info += fmt.Sprintf("%+v, ", current)
|
info += fmt.Sprintf("%+v, ", current)
|
||||||
@@ -229,13 +226,13 @@ func (link *DoublyLink[T]) Print() {
|
|||||||
fmt.Println(info)
|
fmt.Println(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEmpty checks if link is empty or not
|
// IsEmpty checks if dl is empty or not
|
||||||
func (link *DoublyLink[T]) IsEmpty() bool {
|
func (dl *DoublyLink[T]) IsEmpty() bool {
|
||||||
return link.length == 0
|
return dl.length == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear all nodes in doubly linklist
|
// Clear all nodes in doubly linklist
|
||||||
func (link *DoublyLink[T]) Clear() {
|
func (dl *DoublyLink[T]) Clear() {
|
||||||
link.Head = nil
|
dl.Head = nil
|
||||||
link.length = 0
|
dl.length = 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,29 +41,24 @@ func TestDoublyLink_InsertAt(t *testing.T) {
|
|||||||
|
|
||||||
link := NewDoublyLink[int]()
|
link := NewDoublyLink[int]()
|
||||||
|
|
||||||
err := link.InsertAt(1, 1)
|
link.InsertAt(1, 1) //do nothing
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
link.InsertAt(0, 1)
|
link.InsertAt(0, 1)
|
||||||
link.InsertAt(1, 2)
|
link.InsertAt(1, 2)
|
||||||
link.InsertAt(2, 4)
|
link.InsertAt(2, 4)
|
||||||
link.InsertAt(2, 3)
|
link.InsertAt(2, 3)
|
||||||
|
|
||||||
link.Print()
|
|
||||||
|
|
||||||
expected := []int{1, 2, 3, 4}
|
expected := []int{1, 2, 3, 4}
|
||||||
values := link.Values()
|
values := link.Values()
|
||||||
|
|
||||||
assert.Equal(expected, values)
|
assert.Equal(expected, values)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDoublyLink_DeleteAtHead(t *testing.T) {
|
func TestDoublyLink_DeleteAtHead(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtHead")
|
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtHead")
|
||||||
|
|
||||||
link := NewDoublyLink[int]()
|
link := NewDoublyLink[int]()
|
||||||
err := link.DeleteAtHead()
|
link.DeleteAtHead()
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
link.InsertAtTail(1)
|
link.InsertAtTail(1)
|
||||||
link.InsertAtTail(2)
|
link.InsertAtTail(2)
|
||||||
@@ -71,7 +66,6 @@ func TestDoublyLink_DeleteAtHead(t *testing.T) {
|
|||||||
link.InsertAtTail(4)
|
link.InsertAtTail(4)
|
||||||
|
|
||||||
link.DeleteAtHead()
|
link.DeleteAtHead()
|
||||||
link.Print()
|
|
||||||
|
|
||||||
expected := []int{2, 3, 4}
|
expected := []int{2, 3, 4}
|
||||||
values := link.Values()
|
values := link.Values()
|
||||||
@@ -83,8 +77,7 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtTail")
|
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtTail")
|
||||||
|
|
||||||
link := NewDoublyLink[int]()
|
link := NewDoublyLink[int]()
|
||||||
err := link.DeleteAtTail()
|
link.DeleteAtTail()
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
link.InsertAtTail(1)
|
link.InsertAtTail(1)
|
||||||
link.InsertAtTail(2)
|
link.InsertAtTail(2)
|
||||||
@@ -92,7 +85,6 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
|
|||||||
link.InsertAtTail(4)
|
link.InsertAtTail(4)
|
||||||
|
|
||||||
link.DeleteAtTail()
|
link.DeleteAtTail()
|
||||||
link.Print()
|
|
||||||
|
|
||||||
expected := []int{1, 2, 3}
|
expected := []int{1, 2, 3}
|
||||||
values := link.Values()
|
values := link.Values()
|
||||||
@@ -104,8 +96,7 @@ func TestDoublyLink_DeleteAt(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAt")
|
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAt")
|
||||||
|
|
||||||
link := NewDoublyLink[int]()
|
link := NewDoublyLink[int]()
|
||||||
err := link.DeleteAt(0)
|
link.DeleteAt(0)
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
link.InsertAtTail(1)
|
link.InsertAtTail(1)
|
||||||
link.InsertAtTail(2)
|
link.InsertAtTail(2)
|
||||||
@@ -113,11 +104,7 @@ func TestDoublyLink_DeleteAt(t *testing.T) {
|
|||||||
link.InsertAtTail(4)
|
link.InsertAtTail(4)
|
||||||
link.InsertAtTail(5)
|
link.InsertAtTail(5)
|
||||||
|
|
||||||
err = link.DeleteAt(5)
|
link.DeleteAt(0)
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
err = link.DeleteAt(0)
|
|
||||||
assert.IsNil(err)
|
|
||||||
assert.Equal([]int{2, 3, 4, 5}, link.Values())
|
assert.Equal([]int{2, 3, 4, 5}, link.Values())
|
||||||
|
|
||||||
link.DeleteAt(3)
|
link.DeleteAt(3)
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
package datastructure
|
package datastructure
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/datastructure"
|
"github.com/duke-git/lancet/v2/datastructure"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SinglyLink is a linked list. Whose node has a Value generics and Next pointer points to a next node of the link.
|
// SinglyLink is a linked list. Whose node has a Value generics and Next pointer points to a next node of the sl.
|
||||||
type SinglyLink[T any] struct {
|
type SinglyLink[T any] struct {
|
||||||
Head *datastructure.LinkNode[T]
|
Head *datastructure.LinkNode[T]
|
||||||
length int
|
length int
|
||||||
@@ -20,18 +19,18 @@ func NewSinglyLink[T any]() *SinglyLink[T] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// InsertAtHead insert value into singly linklist at head index
|
// InsertAtHead insert value into singly linklist at head index
|
||||||
func (link *SinglyLink[T]) InsertAtHead(value T) {
|
func (sl *SinglyLink[T]) InsertAtHead(value T) {
|
||||||
newNode := datastructure.NewLinkNode(value)
|
newNode := datastructure.NewLinkNode(value)
|
||||||
newNode.Next = link.Head
|
newNode.Next = sl.Head
|
||||||
link.Head = newNode
|
sl.Head = newNode
|
||||||
link.length++
|
sl.length++
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertAtTail insert value into singly linklist at tail index
|
// InsertAtTail insert value into singly linklist at tail index
|
||||||
func (link *SinglyLink[T]) InsertAtTail(value T) {
|
func (sl *SinglyLink[T]) InsertAtTail(value T) {
|
||||||
current := link.Head
|
current := sl.Head
|
||||||
if current == nil {
|
if current == nil {
|
||||||
link.InsertAtHead(value)
|
sl.InsertAtHead(value)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,65 +42,63 @@ func (link *SinglyLink[T]) InsertAtTail(value T) {
|
|||||||
newNode.Next = nil
|
newNode.Next = nil
|
||||||
current.Next = newNode
|
current.Next = newNode
|
||||||
|
|
||||||
link.length++
|
sl.length++
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertAt insert value into singly linklist at index
|
// InsertAt insert value into singly linklist at index
|
||||||
func (link *SinglyLink[T]) InsertAt(index int, value T) error {
|
// param `index` should between [0, len(SinglyLink)], if index do not meet the conditions, do nothing
|
||||||
size := link.length
|
func (sl *SinglyLink[T]) InsertAt(index int, value T) {
|
||||||
|
size := sl.length
|
||||||
if index < 0 || index > size {
|
if index < 0 || index > size {
|
||||||
return errors.New("param index should between 0 and the length of singly link.")
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
link.InsertAtHead(value)
|
sl.InsertAtHead(value)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == size {
|
if index == size {
|
||||||
link.InsertAtTail(value)
|
sl.InsertAtTail(value)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
current := link.Head
|
current := sl.Head
|
||||||
|
|
||||||
for current != nil {
|
for current != nil {
|
||||||
if i == index-1 {
|
if i == index-1 {
|
||||||
newNode := datastructure.NewLinkNode(value)
|
newNode := datastructure.NewLinkNode(value)
|
||||||
newNode.Next = current.Next
|
newNode.Next = current.Next
|
||||||
current.Next = newNode
|
current.Next = newNode
|
||||||
link.length++
|
sl.length++
|
||||||
|
return
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
current = current.Next
|
current = current.Next
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New("singly link list no exist")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAtHead delete value in singly linklist at head index
|
// DeleteAtHead delete value in singly linklist at head index
|
||||||
func (link *SinglyLink[T]) DeleteAtHead() error {
|
func (sl *SinglyLink[T]) DeleteAtHead() {
|
||||||
if link.Head == nil {
|
if sl.Head == nil {
|
||||||
return errors.New("singly link list no exist")
|
return
|
||||||
}
|
}
|
||||||
current := link.Head
|
|
||||||
link.Head = current.Next
|
|
||||||
link.length--
|
|
||||||
|
|
||||||
return nil
|
current := sl.Head
|
||||||
|
sl.Head = current.Next
|
||||||
|
sl.length--
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAtTail delete value in singly linklist at tail index
|
// DeleteAtTail delete value in singly linklist at tail
|
||||||
func (link *SinglyLink[T]) DeleteAtTail() error {
|
func (sl *SinglyLink[T]) DeleteAtTail() {
|
||||||
if link.Head == nil {
|
if sl.Head == nil {
|
||||||
return errors.New("singly link list no exist")
|
return
|
||||||
}
|
}
|
||||||
current := link.Head
|
|
||||||
|
current := sl.Head
|
||||||
if current.Next == nil {
|
if current.Next == nil {
|
||||||
return link.DeleteAtHead()
|
sl.DeleteAtHead()
|
||||||
}
|
}
|
||||||
|
|
||||||
for current.Next.Next != nil {
|
for current.Next.Next != nil {
|
||||||
@@ -109,68 +106,66 @@ func (link *SinglyLink[T]) DeleteAtTail() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
current.Next = nil
|
current.Next = nil
|
||||||
link.length--
|
sl.length--
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteAt delete value in singly linklist at index
|
// DeleteAt delete value in singly linklist at index
|
||||||
func (link *SinglyLink[T]) DeleteAt(index int) error {
|
// param `index` should be [0, len(SinglyLink)-1]
|
||||||
if link.Head == nil {
|
func (sl *SinglyLink[T]) DeleteAt(index int) {
|
||||||
return errors.New("singly link list no exist")
|
if sl.Head == nil {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
current := link.Head
|
current := sl.Head
|
||||||
if current.Next == nil || index == 0 {
|
if current.Next == nil || index == 0 {
|
||||||
return link.DeleteAtHead()
|
sl.DeleteAtHead()
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == link.length-1 {
|
if index == sl.length-1 {
|
||||||
return link.DeleteAtTail()
|
sl.DeleteAtTail()
|
||||||
}
|
}
|
||||||
|
|
||||||
if index < 0 || index > link.length-1 {
|
if index < 0 || index > sl.length-1 {
|
||||||
return errors.New("param index should between 0 and link size -1.")
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
for current != nil {
|
for current != nil {
|
||||||
if i == index-1 {
|
if i == index-1 {
|
||||||
current.Next = current.Next.Next
|
current.Next = current.Next.Next
|
||||||
link.length--
|
sl.length--
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
current = current.Next
|
current = current.Next
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New("delete error")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteValue delete value in singly linklist
|
// DeleteValue delete value in singly linklist
|
||||||
func (link *SinglyLink[T]) DeleteValue(value T) {
|
func (sl *SinglyLink[T]) DeleteValue(value T) {
|
||||||
if link.Head == nil {
|
if sl.Head == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dummyHead := datastructure.NewLinkNode(value)
|
dummyHead := datastructure.NewLinkNode(value)
|
||||||
dummyHead.Next = link.Head
|
dummyHead.Next = sl.Head
|
||||||
current := dummyHead
|
current := dummyHead
|
||||||
|
|
||||||
for current.Next != nil {
|
for current.Next != nil {
|
||||||
if reflect.DeepEqual(current.Next.Value, value) {
|
if reflect.DeepEqual(current.Next.Value, value) {
|
||||||
current.Next = current.Next.Next
|
current.Next = current.Next.Next
|
||||||
link.length--
|
sl.length--
|
||||||
} else {
|
} else {
|
||||||
current = current.Next
|
current = current.Next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
link.Head = dummyHead.Next
|
sl.Head = dummyHead.Next
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reverse the linked list
|
// Reverse the linked list
|
||||||
func (link *SinglyLink[T]) Reverse() {
|
func (sl *SinglyLink[T]) Reverse() {
|
||||||
var pre, next *datastructure.LinkNode[T]
|
var pre, next *datastructure.LinkNode[T]
|
||||||
|
|
||||||
current := link.Head
|
current := sl.Head
|
||||||
|
|
||||||
for current != nil {
|
for current != nil {
|
||||||
next = current.Next
|
next = current.Next
|
||||||
@@ -179,19 +174,19 @@ func (link *SinglyLink[T]) Reverse() {
|
|||||||
current = next
|
current = next
|
||||||
}
|
}
|
||||||
|
|
||||||
link.Head = pre
|
sl.Head = pre
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMiddleNode return node at middle index of linked list
|
// GetMiddleNode return node at middle index of linked list
|
||||||
func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
func (sl *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
||||||
if link.Head == nil {
|
if sl.Head == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if link.Head.Next == nil {
|
if sl.Head.Next == nil {
|
||||||
return link.Head
|
return sl.Head
|
||||||
}
|
}
|
||||||
fast := link.Head
|
fast := sl.Head
|
||||||
slow := link.Head
|
slow := sl.Head
|
||||||
|
|
||||||
for fast != nil {
|
for fast != nil {
|
||||||
fast = fast.Next
|
fast = fast.Next
|
||||||
@@ -207,14 +202,14 @@ func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Size return the count of singly linked list
|
// Size return the count of singly linked list
|
||||||
func (link *SinglyLink[T]) Size() int {
|
func (sl *SinglyLink[T]) Size() int {
|
||||||
return link.length
|
return sl.length
|
||||||
}
|
}
|
||||||
|
|
||||||
// Values return slice of all singly linklist node value
|
// Values return slice of all singly linklist node value
|
||||||
func (link *SinglyLink[T]) Values() []T {
|
func (sl *SinglyLink[T]) Values() []T {
|
||||||
result := []T{}
|
result := []T{}
|
||||||
current := link.Head
|
current := sl.Head
|
||||||
for current != nil {
|
for current != nil {
|
||||||
result = append(result, current.Value)
|
result = append(result, current.Value)
|
||||||
current = current.Next
|
current = current.Next
|
||||||
@@ -222,20 +217,20 @@ func (link *SinglyLink[T]) Values() []T {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsEmpty checks if link is empty or not
|
// IsEmpty checks if sl is empty or not
|
||||||
func (link *SinglyLink[T]) IsEmpty() bool {
|
func (sl *SinglyLink[T]) IsEmpty() bool {
|
||||||
return link.length == 0
|
return sl.length == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear all the node in singly linklist
|
// Clear all the node in singly linklist
|
||||||
func (link *SinglyLink[T]) Clear() {
|
func (sl *SinglyLink[T]) Clear() {
|
||||||
link.Head = nil
|
sl.Head = nil
|
||||||
link.length = 0
|
sl.length = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print all nodes info of a linked list
|
// Print all nodes info of a linked list
|
||||||
func (link *SinglyLink[T]) Print() {
|
func (sl *SinglyLink[T]) Print() {
|
||||||
current := link.Head
|
current := sl.Head
|
||||||
info := "[ "
|
info := "[ "
|
||||||
for current != nil {
|
for current != nil {
|
||||||
info += fmt.Sprintf("%+v, ", current)
|
info += fmt.Sprintf("%+v, ", current)
|
||||||
|
|||||||
@@ -41,25 +41,12 @@ func TestSinglyLink_InsertAt(t *testing.T) {
|
|||||||
|
|
||||||
link := NewSinglyLink[int]()
|
link := NewSinglyLink[int]()
|
||||||
|
|
||||||
err := link.InsertAt(1, 1)
|
link.InsertAt(1, 1) //do nothing
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
err = link.InsertAt(0, 1)
|
link.InsertAt(0, 1)
|
||||||
if err != nil {
|
link.InsertAt(1, 2)
|
||||||
t.FailNow()
|
link.InsertAt(2, 4)
|
||||||
}
|
link.InsertAt(2, 3)
|
||||||
err = link.InsertAt(1, 2)
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
err = link.InsertAt(2, 4)
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
err = link.InsertAt(2, 3)
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
link.Print()
|
link.Print()
|
||||||
|
|
||||||
@@ -73,8 +60,8 @@ func TestSinglyLink_DeleteAtHead(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtHead")
|
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtHead")
|
||||||
|
|
||||||
link := NewSinglyLink[int]()
|
link := NewSinglyLink[int]()
|
||||||
err := link.DeleteAtHead()
|
|
||||||
assert.IsNotNil(err)
|
link.DeleteAtHead()
|
||||||
|
|
||||||
link.InsertAtTail(1)
|
link.InsertAtTail(1)
|
||||||
link.InsertAtTail(2)
|
link.InsertAtTail(2)
|
||||||
@@ -94,8 +81,6 @@ func TestSinglyLink_DeleteAtTail(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtTail")
|
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtTail")
|
||||||
|
|
||||||
link := NewSinglyLink[int]()
|
link := NewSinglyLink[int]()
|
||||||
err := link.DeleteAtTail()
|
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
link.InsertAtTail(1)
|
link.InsertAtTail(1)
|
||||||
link.InsertAtTail(2)
|
link.InsertAtTail(2)
|
||||||
@@ -103,7 +88,6 @@ func TestSinglyLink_DeleteAtTail(t *testing.T) {
|
|||||||
link.InsertAtTail(4)
|
link.InsertAtTail(4)
|
||||||
|
|
||||||
link.DeleteAtTail()
|
link.DeleteAtTail()
|
||||||
link.Print()
|
|
||||||
|
|
||||||
expected := []int{1, 2, 3}
|
expected := []int{1, 2, 3}
|
||||||
values := link.Values()
|
values := link.Values()
|
||||||
@@ -133,8 +117,6 @@ func TestSinglyLink_DeleteAt(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAt")
|
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAt")
|
||||||
|
|
||||||
link := NewSinglyLink[int]()
|
link := NewSinglyLink[int]()
|
||||||
err := link.DeleteAt(0)
|
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
link.InsertAtTail(1)
|
link.InsertAtTail(1)
|
||||||
link.InsertAtTail(2)
|
link.InsertAtTail(2)
|
||||||
@@ -142,11 +124,7 @@ func TestSinglyLink_DeleteAt(t *testing.T) {
|
|||||||
link.InsertAtTail(4)
|
link.InsertAtTail(4)
|
||||||
link.InsertAtTail(5)
|
link.InsertAtTail(5)
|
||||||
|
|
||||||
err = link.DeleteAt(5)
|
link.DeleteAt(0)
|
||||||
assert.IsNotNil(err)
|
|
||||||
|
|
||||||
err = link.DeleteAt(0)
|
|
||||||
assert.IsNil(err)
|
|
||||||
assert.Equal([]int{2, 3, 4, 5}, link.Values())
|
assert.Equal([]int{2, 3, 4, 5}, link.Values())
|
||||||
|
|
||||||
link.DeleteAt(3)
|
link.DeleteAt(3)
|
||||||
@@ -167,7 +145,6 @@ func TestSinglyLink_Reverse(t *testing.T) {
|
|||||||
link.InsertAtTail(4)
|
link.InsertAtTail(4)
|
||||||
|
|
||||||
link.Reverse()
|
link.Reverse()
|
||||||
link.Print()
|
|
||||||
assert.Equal([]int{4, 3, 2, 1}, link.Values())
|
assert.Equal([]int{4, 3, 2, 1}, link.Values())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,17 +8,17 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
// List is a linear table, implemented with slice
|
// List is a linear table, implemented with slice.
|
||||||
type List[T any] struct {
|
type List[T any] struct {
|
||||||
data []T
|
data []T
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewList return a pointer of List
|
// NewList return a pointer of List.
|
||||||
func NewList[T any](data []T) *List[T] {
|
func NewList[T any](data []T) *List[T] {
|
||||||
return &List[T]{data: data}
|
return &List[T]{data: data}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data return list data
|
// Data return list data.
|
||||||
func (l *List[T]) Data() []T {
|
func (l *List[T]) Data() []T {
|
||||||
return l.data
|
return l.data
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ func (l *List[T]) ValueOf(index int) (*T, bool) {
|
|||||||
return &l.data[index], true
|
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 {
|
func (l *List[T]) IndexOf(value T) int {
|
||||||
index := -1
|
index := -1
|
||||||
data := l.data
|
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.
|
// 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 {
|
func (l *List[T]) LastIndexOf(value T) int {
|
||||||
index := -1
|
index := -1
|
||||||
data := l.data
|
data := l.data
|
||||||
@@ -59,7 +59,7 @@ func (l *List[T]) LastIndexOf(value T) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IndexOfFunc returns the first index satisfying f(v)
|
// 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 {
|
func (l *List[T]) IndexOfFunc(f func(T) bool) int {
|
||||||
index := -1
|
index := -1
|
||||||
data := l.data
|
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])
|
// 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 {
|
func (l *List[T]) LastIndexOfFunc(f func(T) bool) int {
|
||||||
index := -1
|
index := -1
|
||||||
data := l.data
|
data := l.data
|
||||||
@@ -86,7 +86,7 @@ func (l *List[T]) LastIndexOfFunc(f func(T) bool) int {
|
|||||||
return index
|
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 {
|
func (l *List[T]) Contain(value T) bool {
|
||||||
data := l.data
|
data := l.data
|
||||||
for _, v := range data {
|
for _, v := range data {
|
||||||
@@ -97,22 +97,22 @@ func (l *List[T]) Contain(value T) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push append value to the list data
|
// Push append value to the list data.
|
||||||
func (l *List[T]) Push(value T) {
|
func (l *List[T]) Push(value T) {
|
||||||
l.data = append(l.data, value)
|
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) {
|
func (l *List[T]) InsertAtFirst(value T) {
|
||||||
l.InsertAt(0, value)
|
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) {
|
func (l *List[T]) InsertAtLast(value T) {
|
||||||
l.InsertAt(len(l.data), value)
|
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) {
|
func (l *List[T]) InsertAt(index int, value T) {
|
||||||
data := l.data
|
data := l.data
|
||||||
size := len(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:]...)...)
|
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) {
|
func (l *List[T]) PopFirst() (*T, bool) {
|
||||||
if len(l.data) == 0 {
|
if len(l.data) == 0 {
|
||||||
return nil, false
|
return nil, false
|
||||||
@@ -135,7 +135,7 @@ func (l *List[T]) PopFirst() (*T, bool) {
|
|||||||
return &v, true
|
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) {
|
func (l *List[T]) PopLast() (*T, bool) {
|
||||||
size := len(l.data)
|
size := len(l.data)
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
@@ -148,7 +148,7 @@ func (l *List[T]) PopLast() (*T, bool) {
|
|||||||
return &v, true
|
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) {
|
func (l *List[T]) DeleteAt(index int) {
|
||||||
data := l.data
|
data := l.data
|
||||||
size := len(data)
|
size := len(data)
|
||||||
@@ -156,7 +156,7 @@ func (l *List[T]) DeleteAt(index int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if index == size-1 {
|
if index == size-1 {
|
||||||
data = append(data[:index])
|
data = data[:index]
|
||||||
} else {
|
} else {
|
||||||
data = append(data[:index], data[index+1:]...)
|
data = append(data[:index], data[index+1:]...)
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ func (l *List[T]) DeleteIf(f func(T) bool) int {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if index == size-1 {
|
if index == size-1 {
|
||||||
data = append(data[:index])
|
data = data[:index]
|
||||||
} else {
|
} else {
|
||||||
data = append(data[:index], data[index+1:]...)
|
data = append(data[:index], data[index+1:]...)
|
||||||
index--
|
index--
|
||||||
@@ -199,7 +199,7 @@ func (l *List[T]) UpdateAt(index int, value T) {
|
|||||||
l.data = append(data[:index], append([]T{value}, data[index+1:]...)...)
|
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 {
|
func (l *List[T]) Equal(other *List[T]) bool {
|
||||||
if len(l.data) != len(other.data) {
|
if len(l.data) != len(other.data) {
|
||||||
return false
|
return false
|
||||||
@@ -214,17 +214,17 @@ func (l *List[T]) Equal(other *List[T]) bool {
|
|||||||
return true
|
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 {
|
func (l *List[T]) IsEmpty() bool {
|
||||||
return len(l.data) == 0
|
return len(l.data) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the data of list
|
// Clear the data of list.
|
||||||
func (l *List[T]) Clear() {
|
func (l *List[T]) Clear() {
|
||||||
l.data = make([]T, 0, 0)
|
l.data = make([]T, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone return a copy of list
|
// Clone return a copy of list.
|
||||||
func (l *List[T]) Clone() *List[T] {
|
func (l *List[T]) Clone() *List[T] {
|
||||||
cl := NewList(make([]T, len(l.data)))
|
cl := NewList(make([]T, len(l.data)))
|
||||||
copy(cl.data, l.data)
|
copy(cl.data, l.data)
|
||||||
@@ -232,10 +232,10 @@ func (l *List[T]) Clone() *List[T] {
|
|||||||
return cl
|
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] {
|
func (l *List[T]) Merge(other *List[T]) *List[T] {
|
||||||
l1, l2 := len(l.data), len(other.data)
|
l1, l2 := len(l.data), len(other.data)
|
||||||
ml := NewList(make([]T, l1+l2, l1+l2))
|
ml := NewList(make([]T, l1+l2))
|
||||||
|
|
||||||
data := append([]T{}, append(l.data, other.data...)...)
|
data := append([]T{}, append(l.data, other.data...)...)
|
||||||
ml.data = data
|
ml.data = data
|
||||||
@@ -243,17 +243,17 @@ func (l *List[T]) Merge(other *List[T]) *List[T] {
|
|||||||
return ml
|
return ml
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size return number of list data items
|
// Size return number of list data items.
|
||||||
func (l *List[T]) Size() int {
|
func (l *List[T]) Size() int {
|
||||||
return len(l.data)
|
return len(l.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cap return cap of the inner data
|
// Cap return cap of the inner data.
|
||||||
func (l *List[T]) Cap() int {
|
func (l *List[T]) Cap() int {
|
||||||
return cap(l.data)
|
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) {
|
func (l *List[T]) Swap(i, j int) {
|
||||||
size := len(l.data)
|
size := len(l.data)
|
||||||
if i < 0 || i >= size || j < 0 || j >= size {
|
if i < 0 || i >= size || j < 0 || j >= size {
|
||||||
@@ -262,19 +262,19 @@ func (l *List[T]) Swap(i, j int) {
|
|||||||
l.data[i], l.data[j] = l.data[j], l.data[i]
|
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() {
|
func (l *List[T]) Reverse() {
|
||||||
for i, j := 0, len(l.data)-1; i < j; i, j = i+1, j-1 {
|
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]
|
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() {
|
func (l *List[T]) Unique() {
|
||||||
data := l.data
|
data := l.data
|
||||||
size := len(data)
|
size := len(data)
|
||||||
|
|
||||||
uniqueData := make([]T, 0, 0)
|
uniqueData := make([]T, 0)
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
value := data[i]
|
value := data[i]
|
||||||
skip := true
|
skip := true
|
||||||
@@ -303,9 +303,9 @@ func (l *List[T]) Union(other *List[T]) *List[T] {
|
|||||||
return result
|
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] {
|
func (l *List[T]) Intersection(other *List[T]) *List[T] {
|
||||||
result := NewList(make([]T, 0, 0))
|
result := NewList(make([]T, 0))
|
||||||
|
|
||||||
for _, v := range l.data {
|
for _, v := range l.data {
|
||||||
if other.Contain(v) {
|
if other.Contain(v) {
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ func TestArrayQueue_Enqueue(t *testing.T) {
|
|||||||
data := queue.Data()
|
data := queue.Data()
|
||||||
size := queue.Size()
|
size := queue.Size()
|
||||||
|
|
||||||
queue.Print()
|
|
||||||
|
|
||||||
assert.Equal(expected, data)
|
assert.Equal(expected, data)
|
||||||
assert.Equal(3, size)
|
assert.Equal(3, size)
|
||||||
}
|
}
|
||||||
@@ -35,7 +33,6 @@ func TestArrayQueue_Dequeue(t *testing.T) {
|
|||||||
val, ok := queue.Dequeue()
|
val, ok := queue.Dequeue()
|
||||||
assert.Equal(true, ok)
|
assert.Equal(true, ok)
|
||||||
|
|
||||||
queue.Print()
|
|
||||||
assert.Equal(1, val)
|
assert.Equal(1, val)
|
||||||
assert.Equal([]int{2, 3}, queue.Data())
|
assert.Equal([]int{2, 3}, queue.Data())
|
||||||
}
|
}
|
||||||
@@ -50,8 +47,6 @@ func TestArrayQueue_Front(t *testing.T) {
|
|||||||
|
|
||||||
val := queue.Front()
|
val := queue.Front()
|
||||||
|
|
||||||
queue.Print()
|
|
||||||
|
|
||||||
assert.Equal(1, val)
|
assert.Equal(1, val)
|
||||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||||
}
|
}
|
||||||
@@ -66,8 +61,6 @@ func TestArrayQueue_Back(t *testing.T) {
|
|||||||
|
|
||||||
val := queue.Back()
|
val := queue.Back()
|
||||||
|
|
||||||
queue.Print()
|
|
||||||
|
|
||||||
assert.Equal(3, val)
|
assert.Equal(3, val)
|
||||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,31 +10,43 @@ func TestCircularQueue_Enqueue(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestCircularQueue_Enqueue")
|
assert := internal.NewAssert(t, "TestCircularQueue_Enqueue")
|
||||||
|
|
||||||
queue := NewCircularQueue[int](6)
|
queue := NewCircularQueue[int](6)
|
||||||
queue.Enqueue(1)
|
|
||||||
queue.Enqueue(2)
|
|
||||||
queue.Enqueue(3)
|
|
||||||
queue.Enqueue(4)
|
|
||||||
queue.Enqueue(5)
|
|
||||||
|
|
||||||
queue.Print()
|
err := queue.Enqueue(1)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = queue.Enqueue(2)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = queue.Enqueue(3)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = queue.Enqueue(4)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = queue.Enqueue(5)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
|
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
|
||||||
assert.Equal(5, queue.Size())
|
assert.Equal(5, queue.Size())
|
||||||
|
|
||||||
err := queue.Enqueue(6)
|
err = queue.Enqueue(6)
|
||||||
assert.IsNotNil(err)
|
assert.IsNotNil(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCircularQueue_Dequeue(t *testing.T) {
|
func TestCircularQueue_Dequeue(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestCircularQueue_DeQueue")
|
assert := internal.NewAssert(t, "TestCircularQueue_DeQueue")
|
||||||
|
|
||||||
queue := NewCircularQueue[int](6)
|
queue := NewCircularQueue[int](4)
|
||||||
assert.Equal(true, queue.IsEmpty())
|
assert.Equal(true, queue.IsEmpty())
|
||||||
|
|
||||||
queue.Enqueue(1)
|
err := queue.Enqueue(1)
|
||||||
queue.Enqueue(2)
|
assert.IsNil(err)
|
||||||
queue.Enqueue(3)
|
|
||||||
queue.Enqueue(4)
|
err = queue.Enqueue(2)
|
||||||
queue.Enqueue(5)
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = queue.Enqueue(3)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
val, err := queue.Dequeue()
|
val, err := queue.Dequeue()
|
||||||
assert.IsNil(err)
|
assert.IsNil(err)
|
||||||
@@ -43,11 +55,7 @@ func TestCircularQueue_Dequeue(t *testing.T) {
|
|||||||
assert.Equal(false, queue.IsFull())
|
assert.Equal(false, queue.IsFull())
|
||||||
|
|
||||||
val, _ = queue.Dequeue()
|
val, _ = queue.Dequeue()
|
||||||
queue.Print()
|
|
||||||
assert.Equal(2, *val)
|
assert.Equal(2, *val)
|
||||||
|
|
||||||
queue.Enqueue(6)
|
|
||||||
queue.Print()
|
|
||||||
assert.Equal(false, queue.IsFull())
|
assert.Equal(false, queue.IsFull())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,55 +63,52 @@ func TestCircularQueue_Front(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestCircularQueue_Front")
|
assert := internal.NewAssert(t, "TestCircularQueue_Front")
|
||||||
|
|
||||||
queue := NewCircularQueue[int](6)
|
queue := NewCircularQueue[int](6)
|
||||||
queue.Enqueue(1)
|
|
||||||
queue.Enqueue(2)
|
|
||||||
queue.Enqueue(3)
|
|
||||||
queue.Enqueue(4)
|
|
||||||
queue.Enqueue(5)
|
|
||||||
|
|
||||||
queue.Print()
|
err := queue.Enqueue(1)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
queue.Dequeue()
|
err = queue.Enqueue(2)
|
||||||
queue.Dequeue()
|
assert.IsNil(err)
|
||||||
queue.Enqueue(6)
|
|
||||||
queue.Enqueue(7)
|
|
||||||
|
|
||||||
queue.Print()
|
err = queue.Enqueue(3)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
val := queue.Front()
|
val := queue.Front()
|
||||||
assert.Equal(3, val)
|
assert.IsNil(err)
|
||||||
assert.Equal(5, queue.Size())
|
assert.Equal(1, val)
|
||||||
|
assert.Equal(3, queue.Size())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCircularQueue_Back(t *testing.T) {
|
func TestCircularQueue_Back(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestCircularQueue_Back")
|
assert := internal.NewAssert(t, "TestCircularQueue_Back")
|
||||||
|
|
||||||
queue := NewCircularQueue[int](6)
|
queue := NewCircularQueue[int](3)
|
||||||
assert.Equal(true, queue.IsEmpty())
|
assert.Equal(true, queue.IsEmpty())
|
||||||
|
|
||||||
queue.Enqueue(1)
|
err := queue.Enqueue(1)
|
||||||
queue.Enqueue(2)
|
assert.IsNil(err)
|
||||||
queue.Enqueue(3)
|
|
||||||
queue.Enqueue(4)
|
|
||||||
queue.Enqueue(5)
|
|
||||||
|
|
||||||
queue.Print()
|
err = queue.Enqueue(2)
|
||||||
assert.Equal(5, queue.Back())
|
assert.IsNil(err)
|
||||||
|
|
||||||
queue.Dequeue()
|
assert.Equal(2, queue.Back())
|
||||||
queue.Dequeue()
|
|
||||||
queue.Enqueue(6)
|
|
||||||
queue.Enqueue(7)
|
|
||||||
|
|
||||||
queue.Print()
|
val, _ := queue.Dequeue()
|
||||||
assert.Equal(7, queue.Back())
|
assert.Equal(1, *val)
|
||||||
|
|
||||||
|
err = queue.Enqueue(3)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
assert.Equal(3, queue.Back())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCircularQueue_Contain(t *testing.T) {
|
func TestCircularQueue_Contain(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestCircularQueue_Contain")
|
assert := internal.NewAssert(t, "TestCircularQueue_Contain")
|
||||||
|
|
||||||
queue := NewCircularQueue[int](2)
|
queue := NewCircularQueue[int](2)
|
||||||
queue.Enqueue(1)
|
err := queue.Enqueue(1)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
assert.Equal(true, queue.Contain(1))
|
assert.Equal(true, queue.Contain(1))
|
||||||
assert.Equal(false, queue.Contain(2))
|
assert.Equal(false, queue.Contain(2))
|
||||||
}
|
}
|
||||||
@@ -115,7 +120,9 @@ func TestCircularQueue_Clear(t *testing.T) {
|
|||||||
assert.Equal(true, queue.IsEmpty())
|
assert.Equal(true, queue.IsEmpty())
|
||||||
assert.Equal(0, queue.Size())
|
assert.Equal(0, queue.Size())
|
||||||
|
|
||||||
queue.Enqueue(1)
|
err := queue.Enqueue(1)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
assert.Equal(false, queue.IsEmpty())
|
assert.Equal(false, queue.IsEmpty())
|
||||||
assert.Equal(1, queue.Size())
|
assert.Equal(1, queue.Size())
|
||||||
|
|
||||||
@@ -127,22 +134,12 @@ func TestCircularQueue_Clear(t *testing.T) {
|
|||||||
func TestCircularQueue_Data(t *testing.T) {
|
func TestCircularQueue_Data(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestCircularQueue_Data")
|
assert := internal.NewAssert(t, "TestCircularQueue_Data")
|
||||||
|
|
||||||
queue := NewCircularQueue[int](6)
|
queue := NewCircularQueue[int](3)
|
||||||
queue.Enqueue(1)
|
err := queue.Enqueue(1)
|
||||||
queue.Enqueue(2)
|
assert.IsNil(err)
|
||||||
queue.Enqueue(3)
|
|
||||||
queue.Enqueue(4)
|
|
||||||
queue.Enqueue(5)
|
|
||||||
|
|
||||||
queue.Print()
|
err = queue.Enqueue(2)
|
||||||
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
|
assert.IsNil(err)
|
||||||
|
|
||||||
queue.Dequeue()
|
|
||||||
queue.Dequeue()
|
|
||||||
queue.Enqueue(6)
|
|
||||||
queue.Enqueue(7)
|
|
||||||
|
|
||||||
queue.Print()
|
|
||||||
assert.Equal([]int{3, 4, 5, 6, 7}, queue.Data())
|
|
||||||
|
|
||||||
|
assert.Equal([]int{1, 2}, queue.Data())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ func TestLinkedQueue_Enqueue(t *testing.T) {
|
|||||||
queue.Enqueue(2)
|
queue.Enqueue(2)
|
||||||
queue.Enqueue(3)
|
queue.Enqueue(3)
|
||||||
|
|
||||||
queue.Print()
|
|
||||||
|
|
||||||
assert.Equal([]int{1, 2, 3}, queue.Data())
|
assert.Equal([]int{1, 2, 3}, queue.Data())
|
||||||
assert.Equal(3, queue.Size())
|
assert.Equal(3, queue.Size())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,19 +23,24 @@ func TestPriorityQueue_Enqueue(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestPriorityQueue_Enqueue")
|
assert := internal.NewAssert(t, "TestPriorityQueue_Enqueue")
|
||||||
|
|
||||||
comparator := &intComparator{}
|
comparator := &intComparator{}
|
||||||
pq := NewPriorityQueue[int](10, comparator)
|
pq := NewPriorityQueue[int](3, comparator)
|
||||||
|
|
||||||
assert.Equal(true, pq.IsEmpty())
|
assert.Equal(true, pq.IsEmpty())
|
||||||
assert.Equal(false, pq.IsFull())
|
assert.Equal(false, pq.IsFull())
|
||||||
|
|
||||||
for i := 1; i < 11; i++ {
|
err := pq.Enqueue(1)
|
||||||
pq.Enqueue(i)
|
assert.IsNil(err)
|
||||||
}
|
|
||||||
|
err = pq.Enqueue(2)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = pq.Enqueue(3)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
assert.Equal(true, pq.IsFull())
|
assert.Equal(true, pq.IsFull())
|
||||||
|
|
||||||
queueData := pq.Data()
|
queueData := pq.Data()
|
||||||
assert.Equal([]int{10, 9, 6, 7, 8, 2, 5, 1, 4, 3}, queueData)
|
assert.Equal([]int{3, 1, 2}, queueData)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,22 +48,23 @@ func TestPriorityQueue_Dequeue(t *testing.T) {
|
|||||||
assert := internal.NewAssert(t, "TestPriorityQueue_Dequeue")
|
assert := internal.NewAssert(t, "TestPriorityQueue_Dequeue")
|
||||||
|
|
||||||
comparator := &intComparator{}
|
comparator := &intComparator{}
|
||||||
pq := NewPriorityQueue[int](10, comparator)
|
pq := NewPriorityQueue[int](3, comparator)
|
||||||
|
|
||||||
_, ok := pq.Dequeue()
|
_, ok := pq.Dequeue()
|
||||||
assert.Equal(false, ok)
|
assert.Equal(false, ok)
|
||||||
|
|
||||||
for i := 1; i < 11; i++ {
|
err := pq.Enqueue(1)
|
||||||
pq.Enqueue(i)
|
assert.IsNil(err)
|
||||||
}
|
|
||||||
|
|
||||||
assert.Equal(10, pq.Size())
|
err = pq.Enqueue(2)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
err = pq.Enqueue(3)
|
||||||
|
assert.IsNil(err)
|
||||||
|
|
||||||
|
assert.Equal(3, pq.Size())
|
||||||
|
|
||||||
val, ok := pq.Dequeue()
|
val, ok := pq.Dequeue()
|
||||||
assert.Equal(true, ok)
|
assert.Equal(true, ok)
|
||||||
assert.Equal(10, val)
|
assert.Equal(3, val)
|
||||||
|
|
||||||
assert.Equal([]int{9, 8, 6, 7, 3, 2, 5, 1, 4}, pq.Data())
|
|
||||||
|
|
||||||
assert.Equal(9, pq.Size())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ func TestLinkedStack_Push(t *testing.T) {
|
|||||||
stack.Push(2)
|
stack.Push(2)
|
||||||
stack.Push(3)
|
stack.Push(3)
|
||||||
|
|
||||||
stack.Print()
|
|
||||||
|
|
||||||
expected := []int{3, 2, 1}
|
expected := []int{3, 2, 1}
|
||||||
values := stack.Data()
|
values := stack.Data()
|
||||||
size := stack.Size()
|
size := stack.Size()
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ func TestBSTree_Insert(t *testing.T) {
|
|||||||
bstree.Insert(5)
|
bstree.Insert(5)
|
||||||
bstree.Insert(2)
|
bstree.Insert(2)
|
||||||
bstree.Insert(4)
|
bstree.Insert(4)
|
||||||
|
|
||||||
bstree.Print()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBSTree_PreOrderTraverse(t *testing.T) {
|
func TestBSTree_PreOrderTraverse(t *testing.T) {
|
||||||
@@ -86,8 +84,6 @@ func TestBSTree_LevelOrderTraverse(t *testing.T) {
|
|||||||
bstree.Insert(2)
|
bstree.Insert(2)
|
||||||
bstree.Insert(4)
|
bstree.Insert(4)
|
||||||
|
|
||||||
bstree.Print()
|
|
||||||
|
|
||||||
acturl := bstree.LevelOrderTraverse()
|
acturl := bstree.LevelOrderTraverse()
|
||||||
t.Log(acturl)
|
t.Log(acturl)
|
||||||
assert.Equal([]int{6, 5, 7, 2, 4}, acturl)
|
assert.Equal([]int{6, 5, 7, 2, 4}, acturl)
|
||||||
@@ -103,10 +99,8 @@ func TestBSTree_Delete(t *testing.T) {
|
|||||||
bstree.Insert(2)
|
bstree.Insert(2)
|
||||||
bstree.Insert(4)
|
bstree.Insert(4)
|
||||||
|
|
||||||
bstree.Print()
|
|
||||||
|
|
||||||
bstree.Delete(4)
|
bstree.Delete(4)
|
||||||
bstree.Print()
|
|
||||||
acturl1 := bstree.InOrderTraverse()
|
acturl1 := bstree.InOrderTraverse()
|
||||||
t.Log(acturl1)
|
t.Log(acturl1)
|
||||||
assert.Equal([]int{2, 5, 6, 7}, acturl1)
|
assert.Equal([]int{2, 5, 6, 7}, acturl1)
|
||||||
@@ -129,8 +123,6 @@ func TestBSTree_Depth(t *testing.T) {
|
|||||||
bstree.Insert(2)
|
bstree.Insert(2)
|
||||||
bstree.Insert(4)
|
bstree.Insert(4)
|
||||||
|
|
||||||
bstree.Print()
|
|
||||||
|
|
||||||
assert.Equal(bstree.Depth(), 4)
|
assert.Equal(bstree.Depth(), 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,8 +142,6 @@ func TestBSTree_IsSubTree(t *testing.T) {
|
|||||||
subTree.Insert(4)
|
subTree.Insert(4)
|
||||||
subTree.Insert(6)
|
subTree.Insert(6)
|
||||||
|
|
||||||
subTree.Print()
|
|
||||||
|
|
||||||
assert.Equal(true, superTree.HasSubTree(subTree))
|
assert.Equal(true, superTree.HasSubTree(subTree))
|
||||||
assert.Equal(false, subTree.HasSubTree(superTree))
|
assert.Equal(false, subTree.HasSubTree(superTree))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,35 +38,35 @@ func inOrderTraverse[T any](node *datastructure.TreeNode[T]) []T {
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
// func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||||
if node == nil {
|
// if node == nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
fmt.Printf("%v, ", node.Value)
|
// fmt.Printf("%v, ", node.Value)
|
||||||
preOrderPrint(node.Left)
|
// preOrderPrint(node.Left)
|
||||||
preOrderPrint(node.Right)
|
// preOrderPrint(node.Right)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
// func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||||
if node == nil {
|
// if node == nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
preOrderPrint(node.Left)
|
// postOrderPrint(node.Left)
|
||||||
preOrderPrint(node.Right)
|
// postOrderPrint(node.Right)
|
||||||
fmt.Printf("%v, ", node.Value)
|
// fmt.Printf("%v, ", node.Value)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
// func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
|
||||||
if node == nil {
|
// if node == nil {
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
inOrderPrint(node.Left)
|
// inOrderPrint(node.Left)
|
||||||
fmt.Printf("%v, ", node.Value)
|
// fmt.Printf("%v, ", node.Value)
|
||||||
inOrderPrint(node.Right)
|
// inOrderPrint(node.Right)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T) {
|
func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T) {
|
||||||
var q []*datastructure.TreeNode[T] // queue
|
var q []*datastructure.TreeNode[T] // queue
|
||||||
|
|||||||
@@ -9,17 +9,20 @@ type theTime struct {
|
|||||||
unix int64
|
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 {
|
func NewUnixNow() *theTime {
|
||||||
return &theTime{unix: time.Now().Unix()}
|
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 {
|
func NewUnix(unix int64) *theTime {
|
||||||
return &theTime{unix: unix}
|
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) {
|
func NewFormat(t string) (*theTime, error) {
|
||||||
timeLayout := "2006-01-02 15:04:05"
|
timeLayout := "2006-01-02 15:04:05"
|
||||||
loc := time.FixedZone("CST", 8*3600)
|
loc := time.FixedZone("CST", 8*3600)
|
||||||
@@ -30,7 +33,8 @@ func NewFormat(t string) (*theTime, error) {
|
|||||||
return &theTime{unix: tt.Unix()}, nil
|
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) {
|
func NewISO8601(iso8601 string) (*theTime, error) {
|
||||||
t, err := time.ParseInLocation(time.RFC3339, iso8601, time.UTC)
|
t, err := time.ParseInLocation(time.RFC3339, iso8601, time.UTC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -39,22 +43,26 @@ func NewISO8601(iso8601 string) (*theTime, error) {
|
|||||||
return &theTime{unix: t.Unix()}, nil
|
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 {
|
func (t *theTime) ToUnix() int64 {
|
||||||
return t.unix
|
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 {
|
func (t *theTime) ToFormat() string {
|
||||||
return time.Unix(t.unix, 0).Format("2006-01-02 15:04:05")
|
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 {
|
func (t *theTime) ToFormatForTpl(tpl string) string {
|
||||||
return time.Unix(t.unix, 0).Format(tpl)
|
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 {
|
func (t *theTime) ToIso8601() string {
|
||||||
return time.Unix(t.unix, 0).Format(time.RFC3339)
|
return time.Unix(t.unix, 0).Format(time.RFC3339)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,9 +19,6 @@ func TestToUnix(t *testing.T) {
|
|||||||
func TestToFormat(t *testing.T) {
|
func TestToFormat(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestToFormat")
|
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")
|
tm, err := NewFormat("2022-03-18 17:04:05")
|
||||||
assert.IsNil(err)
|
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 {
|
func AddMinute(t time.Time, minute int64) time.Time {
|
||||||
return t.Add(time.Minute * time.Duration(minute))
|
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 {
|
func AddHour(t time.Time, hour int64) time.Time {
|
||||||
return t.Add(time.Hour * time.Duration(hour))
|
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 {
|
func AddDay(t time.Time, day int64) time.Time {
|
||||||
return t.Add(24 * time.Hour * time.Duration(day))
|
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 {
|
func GetNowDate() string {
|
||||||
return time.Now().Format("2006-01-02")
|
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 {
|
func GetNowTime() string {
|
||||||
return time.Now().Format("15:04:05")
|
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 {
|
func GetNowDateTime() string {
|
||||||
return time.Now().Format("2006-01-02 15:04:05")
|
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 {
|
func GetZeroHourTimestamp() int64 {
|
||||||
ts := time.Now().Format("2006-01-02")
|
ts := time.Now().Format("2006-01-02")
|
||||||
t, _ := time.Parse("2006-01-02", ts)
|
t, _ := time.Parse("2006-01-02", ts)
|
||||||
return t.UTC().Unix() - 8*3600
|
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 {
|
func GetNightTimestamp() int64 {
|
||||||
return GetZeroHourTimestamp() + 86400 - 1
|
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 {
|
func FormatTimeToStr(t time.Time, format string) string {
|
||||||
return t.Format(timeFormat[format])
|
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) {
|
func FormatStrToTime(str, format string) (time.Time, error) {
|
||||||
v, ok := timeFormat[format]
|
v, ok := timeFormat[format]
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -111,43 +121,50 @@ func FormatStrToTime(str, format string) (time.Time, error) {
|
|||||||
return time.Parse(v, str)
|
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 {
|
func BeginOfMinute(t time.Time) time.Time {
|
||||||
y, m, d := t.Date()
|
y, m, d := t.Date()
|
||||||
return time.Date(y, m, d, t.Hour(), t.Minute(), 0, 0, t.Location())
|
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 {
|
func EndOfMinute(t time.Time) time.Time {
|
||||||
y, m, d := t.Date()
|
y, m, d := t.Date()
|
||||||
return time.Date(y, m, d, t.Hour(), t.Minute(), 59, int(time.Second-time.Nanosecond), t.Location())
|
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 {
|
func BeginOfHour(t time.Time) time.Time {
|
||||||
y, m, d := t.Date()
|
y, m, d := t.Date()
|
||||||
return time.Date(y, m, d, t.Hour(), 0, 0, 0, t.Location())
|
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 {
|
func EndOfHour(t time.Time) time.Time {
|
||||||
y, m, d := t.Date()
|
y, m, d := t.Date()
|
||||||
return time.Date(y, m, d, t.Hour(), 59, 59, int(time.Second-time.Nanosecond), t.Location())
|
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 {
|
func BeginOfDay(t time.Time) time.Time {
|
||||||
y, m, d := t.Date()
|
y, m, d := t.Date()
|
||||||
return time.Date(y, m, d, 0, 0, 0, 0, t.Location())
|
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 {
|
func EndOfDay(t time.Time) time.Time {
|
||||||
y, m, d := t.Date()
|
y, m, d := t.Date()
|
||||||
return time.Date(y, m, d, 23, 59, 59, int(time.Second-time.Nanosecond), t.Location())
|
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 {
|
func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time {
|
||||||
var beginFromWeekday = time.Sunday
|
var beginFromWeekday = time.Sunday
|
||||||
if len(beginFrom) > 0 {
|
if len(beginFrom) > 0 {
|
||||||
@@ -161,7 +178,8 @@ func BeginOfWeek(t time.Time, beginFrom ...time.Weekday) time.Time {
|
|||||||
return beginOfWeek
|
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 {
|
func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time {
|
||||||
var endWithWeekday = time.Saturday
|
var endWithWeekday = time.Saturday
|
||||||
if len(endWith) > 0 {
|
if len(endWith) > 0 {
|
||||||
@@ -175,24 +193,28 @@ func EndOfWeek(t time.Time, endWith ...time.Weekday) time.Time {
|
|||||||
return endWithWeek
|
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 {
|
func BeginOfMonth(t time.Time) time.Time {
|
||||||
y, m, _ := t.Date()
|
y, m, _ := t.Date()
|
||||||
return time.Date(y, m, 1, 0, 0, 0, 0, t.Location())
|
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 {
|
func EndOfMonth(t time.Time) time.Time {
|
||||||
return BeginOfMonth(t).AddDate(0, 1, 0).Add(-time.Nanosecond)
|
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 {
|
func BeginOfYear(t time.Time) time.Time {
|
||||||
y, _, _ := t.Date()
|
y, _, _ := t.Date()
|
||||||
return time.Date(y, time.January, 1, 0, 0, 0, 0, t.Location())
|
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 {
|
func EndOfYear(t time.Time) time.Time {
|
||||||
return BeginOfYear(t).AddDate(1, 0, 0).Add(-time.Nanosecond)
|
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())
|
assert.Equal(expected, GetNowDate())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetNotTime(t *testing.T) {
|
func TestGetNowTime(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestGetNotTime")
|
assert := internal.NewAssert(t, "TestGetNowTime")
|
||||||
expected := time.Now().Format("15:04:05")
|
expected := time.Now().Format("15:04:05")
|
||||||
assert.Equal(expected, GetNowTime())
|
assert.Equal(expected, GetNowTime())
|
||||||
}
|
}
|
||||||
@@ -81,7 +81,6 @@ func TestFormatTimeToStr(t *testing.T) {
|
|||||||
for i := 0; i < len(cases); i++ {
|
for i := 0; i < len(cases); i++ {
|
||||||
actual := FormatTimeToStr(datetime, cases[i])
|
actual := FormatTimeToStr(datetime, cases[i])
|
||||||
assert.Equal(expected[i], actual)
|
assert.Equal(expected[i], actual)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -570,6 +570,8 @@ func main() {
|
|||||||
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
|
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]) Get(key K) (V, bool)
|
||||||
func (l *LRUCache[K, V]) Put(key K, value V)
|
func (l *LRUCache[K, V]) Put(key K, value V)
|
||||||
|
func (l *LRUCache[K, V]) Delete(key K) bool
|
||||||
|
func (l *LRUCache[K, V]) Len() int
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -586,10 +588,14 @@ func main() {
|
|||||||
|
|
||||||
cache.Put(1, 1)
|
cache.Put(1, 1)
|
||||||
cache.Put(2, 2)
|
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 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]) Get(key K) (V, bool)
|
||||||
func (l *LRUCache[K, V]) Put(key K, value V)
|
func (l *LRUCache[K, V]) Put(key K, value V)
|
||||||
|
func (l *LRUCache[K, V]) Delete(key K) bool
|
||||||
|
func (l *LRUCache[K, V]) Len() int
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -586,10 +588,14 @@ func main() {
|
|||||||
|
|
||||||
cache.Put(1, 1)
|
cache.Put(1, 1)
|
||||||
cache.Put(2, 2)
|
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
|
## Channel
|
||||||
### <span id="NewChannel">NewChannel</span>
|
### <span id="NewChannel">NewChannel</span>
|
||||||
<p>return a Channel pointer instance.</p>
|
<p>Create a Channel pointer instance.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type Channel struct {}
|
type Channel[T any] struct
|
||||||
func NewChannel() *Channel
|
func NewChannel[T any]() *Channel[T]
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[int]()
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -87,25 +87,30 @@ func main() {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[int]()
|
||||||
genVals := func() <-chan <-chan any {
|
genVals := func() <-chan <-chan int {
|
||||||
chanStream := make(chan (<-chan any))
|
out := make(chan (<-chan int))
|
||||||
go func() {
|
go func() {
|
||||||
defer close(chanStream)
|
defer close(out)
|
||||||
for i := 0; i < 10; i++ {
|
for i := 1; i <= 5; i++ {
|
||||||
stream := make(chan any, 1)
|
stream := make(chan int, 1)
|
||||||
stream <- i
|
stream <- i
|
||||||
close(stream)
|
close(stream)
|
||||||
chanStream <- stream
|
out <- stream
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return chanStream
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
index := 0
|
for v := range c.Bridge(ctx, genVals()) {
|
||||||
for val := range c.Bridge(ctx, genVals()) {
|
fmt.Println(v)
|
||||||
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
|
|
||||||
}
|
}
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// 2
|
||||||
|
// 3
|
||||||
|
// 4
|
||||||
|
// 5
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -114,12 +119,12 @@ func main() {
|
|||||||
|
|
||||||
### <span id="FanIn">FanIn</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -136,17 +141,17 @@ func main() {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[int]()
|
||||||
channels := make([]<-chan any, 3)
|
channels := make([]<-chan int, 2)
|
||||||
|
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
mergedChannel := c.FanIn(ctx, channels...)
|
chs := c.FanIn(ctx, channels...)
|
||||||
|
|
||||||
for val := range mergedChannel {
|
for v := range chs {
|
||||||
fmt.Println("\t%d\n", val) //1,2,1,0,0,1,0,2,2 (order not for sure)
|
fmt.Println(v) //1 1 0 0 or 0 0 1 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -154,12 +159,12 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Repeat">Repeat</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -176,26 +181,30 @@ func main() {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[int]()
|
||||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
|
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
||||||
|
|
||||||
for v := range intStream {
|
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>Creates a channel, then put values into the channel.</p>
|
||||||
|
|
||||||
<p>Return a chan, excutes fn repeatly, and put the result into retruned chan until cancel context.</p>
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -212,16 +221,58 @@ func main() {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
fn := func() any {
|
c := concurrency.NewChannel[int]()
|
||||||
s := "a"
|
intStream := c.Generate(ctx, 1, 2, 3)
|
||||||
return s
|
|
||||||
}
|
|
||||||
c := concurrency.NewChannel()
|
|
||||||
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
|
||||||
|
|
||||||
for v := range dataStream {
|
fmt.Println(<-intStream)
|
||||||
fmt.Println(v) //a, a, a
|
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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (c *Channel) Or(channels ...<-chan any) <-chan any
|
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -249,7 +300,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
sig := func(after time.Duration) <-chan any {
|
sig := func(after time.Duration) <-chan any {
|
||||||
c := make(chan interface{})
|
c := make(chan any)
|
||||||
go func() {
|
go func() {
|
||||||
defer close(c)
|
defer close(c)
|
||||||
time.Sleep(after)
|
time.Sleep(after)
|
||||||
@@ -259,13 +310,11 @@ func main() {
|
|||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[any]()
|
||||||
<-c.Or(
|
<-c.Or(
|
||||||
sig(1*time.Second),
|
sig(1*time.Second),
|
||||||
sig(2*time.Second),
|
sig(2*time.Second),
|
||||||
sig(3*time.Second),
|
sig(3*time.Second),
|
||||||
sig(4*time.Second),
|
|
||||||
sig(5*time.Second),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fmt.Println("done after %v", time.Since(start)) //1.003s
|
fmt.Println("done after %v", time.Since(start)) //1.003s
|
||||||
@@ -282,7 +331,7 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -299,12 +348,16 @@ func main() {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[int]()
|
||||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||||
|
|
||||||
for val := range c.OrDone(ctx, intStream) {
|
for v := range c.OrDone(ctx, intStream) {
|
||||||
fmt.Println(val) //1
|
fmt.Println(v)
|
||||||
}
|
}
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// 1
|
||||||
|
// 1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -313,12 +366,12 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Take">Take</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -335,7 +388,7 @@ func main() {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
numbers := make(chan any, 5)
|
numbers := make(chan int, 5)
|
||||||
numbers <- 1
|
numbers <- 1
|
||||||
numbers <- 2
|
numbers <- 2
|
||||||
numbers <- 3
|
numbers <- 3
|
||||||
@@ -343,12 +396,16 @@ func main() {
|
|||||||
numbers <- 5
|
numbers <- 5
|
||||||
defer close(numbers)
|
defer close(numbers)
|
||||||
|
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[int]()
|
||||||
intStream := c.Take(ctx, numbers, 3)
|
intStream := c.Take(ctx, numbers, 3)
|
||||||
|
|
||||||
for val := range intStream {
|
for v := range intStream {
|
||||||
fmt.Println(val) //1, 2, 3
|
fmt.Println(v)
|
||||||
}
|
}
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// 2
|
||||||
|
// 3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -356,12 +413,12 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Tee">Tee</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -378,13 +435,19 @@ func main() {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[int]()
|
||||||
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
|
||||||
|
|
||||||
out1, out2 := c.Tee(ctx, inStream)
|
ch1, ch2 := c.Tee(ctx, intStream)
|
||||||
for val := range out1 {
|
|
||||||
fmt.Println(val) //1
|
for v := range ch1 {
|
||||||
fmt.Println(<-out2) //1
|
fmt.Println(v)
|
||||||
|
fmt.Println(<-ch2)
|
||||||
}
|
}
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// 1
|
||||||
|
// 1
|
||||||
|
// 1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -38,13 +38,13 @@ import (
|
|||||||
|
|
||||||
### Channel
|
### Channel
|
||||||
### <span id="NewChannel">NewChannel</span>
|
### <span id="NewChannel">NewChannel</span>
|
||||||
<p>返回一个 Channel 指针实例</p>
|
<p>返回一个Channel指针实例</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type Channel struct {}
|
type Channel[T any] struct
|
||||||
func NewChannel() *Channel
|
func NewChannel[T any]() *Channel[T]
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[int]()
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -65,12 +65,12 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Bridge">Bridge</span>
|
### <span id="Bridge">Bridge</span>
|
||||||
|
|
||||||
<p>将多个通道链接到一个通道,直到取消上下文。</p>
|
<p>将多个channel链接到一个channel,直到取消上下文。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -84,28 +84,33 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[int]()
|
||||||
genVals := func() <-chan <-chan any {
|
genVals := func() <-chan <-chan int {
|
||||||
chanStream := make(chan (<-chan any))
|
out := make(chan (<-chan int))
|
||||||
go func() {
|
go func() {
|
||||||
defer close(chanStream)
|
defer close(out)
|
||||||
for i := 0; i < 10; i++ {
|
for i := 1; i <= 5; i++ {
|
||||||
stream := make(chan any, 1)
|
stream := make(chan int, 1)
|
||||||
stream <- i
|
stream <- i
|
||||||
close(stream)
|
close(stream)
|
||||||
chanStream <- stream
|
out <- stream
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return chanStream
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
index := 0
|
for v := range c.Bridge(ctx, genVals()) {
|
||||||
for val := range c.Bridge(ctx, genVals()) {
|
fmt.Println(v)
|
||||||
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
|
|
||||||
}
|
}
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// 2
|
||||||
|
// 3
|
||||||
|
// 4
|
||||||
|
// 5
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -114,12 +119,12 @@ func main() {
|
|||||||
|
|
||||||
### <span id="FanIn">FanIn</span>
|
### <span id="FanIn">FanIn</span>
|
||||||
|
|
||||||
<p>将多个通道合并为一个通道,直到取消上下文</p>
|
<p>将多个channel合并为一个channel,直到取消上下文。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -133,33 +138,33 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[int]()
|
||||||
channels := make([]<-chan any, 3)
|
channels := make([]<-chan int, 2)
|
||||||
|
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
|
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
mergedChannel := c.FanIn(ctx, channels...)
|
chs := c.FanIn(ctx, channels...)
|
||||||
|
|
||||||
for val := range mergedChannel {
|
for v := range chs {
|
||||||
fmt.Println("\t%d\n", val) //1,2,1,0,0,1,0,2,2 (order not for sure)
|
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>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -173,15 +178,58 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[int]()
|
||||||
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
|
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 {
|
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>
|
### <span id="RepeatFn">RepeatFn</span>
|
||||||
|
|
||||||
<p>返回一个chan,重复执行函数fn,并将结果放入返回的chan,直到取消上下文。</p>
|
<p>返回一个channel,重复执行函数fn,并将结果放入返回的channel,直到取消上下文。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -209,19 +257,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
fn := func() any {
|
fn := func() string {
|
||||||
s := "a"
|
return "hello"
|
||||||
return s
|
|
||||||
}
|
}
|
||||||
c := concurrency.NewChannel()
|
|
||||||
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
|
|
||||||
|
|
||||||
for v := range dataStream {
|
c := concurrency.NewChannel[string]()
|
||||||
fmt.Println(v) //a, a, a
|
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>
|
### <span id="Or">Or</span>
|
||||||
|
|
||||||
<p>将一个或多个通道读取到一个通道中,当任何读取通道关闭时将结束读取。</p>
|
<p>将一个或多个channel读取到一个channel中,当任何读取channel关闭时将结束读取。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (c *Channel) Or(channels ...<-chan any) <-chan any
|
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -249,7 +301,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
sig := func(after time.Duration) <-chan any {
|
sig := func(after time.Duration) <-chan any {
|
||||||
c := make(chan interface{})
|
c := make(chan any)
|
||||||
go func() {
|
go func() {
|
||||||
defer close(c)
|
defer close(c)
|
||||||
time.Sleep(after)
|
time.Sleep(after)
|
||||||
@@ -259,13 +311,11 @@ func main() {
|
|||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[any]()
|
||||||
<-c.Or(
|
<-c.Or(
|
||||||
sig(1*time.Second),
|
sig(1*time.Second),
|
||||||
sig(2*time.Second),
|
sig(2*time.Second),
|
||||||
sig(3*time.Second),
|
sig(3*time.Second),
|
||||||
sig(4*time.Second),
|
|
||||||
sig(5*time.Second),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fmt.Println("done after %v", time.Since(start)) //1.003s
|
fmt.Println("done after %v", time.Since(start)) //1.003s
|
||||||
@@ -277,12 +327,12 @@ func main() {
|
|||||||
|
|
||||||
### <span id="OrDone">OrDone</span>
|
### <span id="OrDone">OrDone</span>
|
||||||
|
|
||||||
<p>将一个通道读入另一个通道,直到取消上下文。</p>
|
<p>将一个channel读入另一个channel,直到取消上下文。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -299,12 +349,16 @@ func main() {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[int]()
|
||||||
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
|
||||||
|
|
||||||
for val := range c.OrDone(ctx, intStream) {
|
for v := range c.OrDone(ctx, intStream) {
|
||||||
fmt.Println(val) //1
|
fmt.Println(v)
|
||||||
}
|
}
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// 1
|
||||||
|
// 1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -313,12 +367,12 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Take">Take</span>
|
### <span id="Take">Take</span>
|
||||||
|
|
||||||
<p>返回一个chan,其值从另一个chan获取,直到取消上下文。</p>
|
<p>返回一个channel,其值从另一个channel获取,直到取消上下文。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -335,7 +389,7 @@ func main() {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
numbers := make(chan any, 5)
|
numbers := make(chan int, 5)
|
||||||
numbers <- 1
|
numbers <- 1
|
||||||
numbers <- 2
|
numbers <- 2
|
||||||
numbers <- 3
|
numbers <- 3
|
||||||
@@ -343,12 +397,16 @@ func main() {
|
|||||||
numbers <- 5
|
numbers <- 5
|
||||||
defer close(numbers)
|
defer close(numbers)
|
||||||
|
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[int]()
|
||||||
intStream := c.Take(ctx, numbers, 3)
|
intStream := c.Take(ctx, numbers, 3)
|
||||||
|
|
||||||
for val := range intStream {
|
for v := range intStream {
|
||||||
fmt.Println(val) //1, 2, 3
|
fmt.Println(v)
|
||||||
}
|
}
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// 2
|
||||||
|
// 3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -356,12 +414,12 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Tee">Tee</span>
|
### <span id="Tee">Tee</span>
|
||||||
|
|
||||||
<p>将一个通道分成两个通道,直到取消上下文。</p>
|
<p>将一个channel分成两个channel,直到取消上下文。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```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>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -378,13 +436,19 @@ func main() {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
c := concurrency.NewChannel()
|
c := concurrency.NewChannel[int]()
|
||||||
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
|
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
|
||||||
|
|
||||||
out1, out2 := c.Tee(ctx, inStream)
|
ch1, ch2 := c.Tee(ctx, intStream)
|
||||||
for val := range out1 {
|
|
||||||
fmt.Println(val) //1
|
for v := range ch1 {
|
||||||
fmt.Println(<-out2) //1
|
fmt.Println(v)
|
||||||
|
fmt.Println(<-ch2)
|
||||||
}
|
}
|
||||||
|
// Output:
|
||||||
|
// 1
|
||||||
|
// 1
|
||||||
|
// 1
|
||||||
|
// 1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -25,6 +25,7 @@ import (
|
|||||||
- [Or](#Or)
|
- [Or](#Or)
|
||||||
- [Xor](#Generate)
|
- [Xor](#Generate)
|
||||||
- [Nor](#Nor)
|
- [Nor](#Nor)
|
||||||
|
- [Xnor](#Xnor)
|
||||||
- [Nand](#Nand)
|
- [Nand](#Nand)
|
||||||
- [TernaryOperator](#TernaryOperator)
|
- [TernaryOperator](#TernaryOperator)
|
||||||
|
|
||||||
@@ -120,7 +121,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="Or">Or</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -148,7 +149,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="Xor">Xor</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -176,7 +177,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="Nor">Nor</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -197,14 +198,40 @@ func main() {
|
|||||||
fmt.Println(condition.Nor(0, 0)) // true
|
fmt.Println(condition.Nor(0, 0)) // true
|
||||||
fmt.Println(condition.Nor(0, 1)) // false
|
fmt.Println(condition.Nor(0, 1)) // false
|
||||||
fmt.Println(condition.Nor(1, 0)) // 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>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import (
|
|||||||
- [Or](#Or)
|
- [Or](#Or)
|
||||||
- [Xor](#Generate)
|
- [Xor](#Generate)
|
||||||
- [Nor](#Nor)
|
- [Nor](#Nor)
|
||||||
|
- [Xnor](#Xnor)
|
||||||
- [Nand](#Nand)
|
- [Nand](#Nand)
|
||||||
- [TernaryOperator](#TernaryOperator)
|
- [TernaryOperator](#TernaryOperator)
|
||||||
|
|
||||||
@@ -196,12 +197,38 @@ func main() {
|
|||||||
fmt.Println(condition.Nor(0, 0)) // true
|
fmt.Println(condition.Nor(0, 0)) // true
|
||||||
fmt.Println(condition.Nor(0, 1)) // false
|
fmt.Println(condition.Nor(0, 1)) // false
|
||||||
fmt.Println(condition.Nor(1, 0)) // 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>
|
### <span id="Nand">Nand</span>
|
||||||
<p>如果a和b都为真,返回false,否则返回true</p>
|
<p>如果a和b都为真,返回false,否则返回true</p>
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="ToBool">ToBool</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="ToBytes">ToBytes</span>
|
### <span id="ToBytes">ToBytes</span>
|
||||||
|
|
||||||
<p>Convert interface to byte slice.</p>
|
<p>Convert value to byte slice.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="ToChannel">ToChannel</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -238,7 +238,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="ToFloat">ToFloat</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -271,7 +271,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="ToInt">ToInt</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -332,7 +332,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="ToMap">ToMap</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -522,7 +522,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="DecodeByte">DecodeByte</span>
|
### <span id="DecodeByte">DecodeByte</span>
|
||||||
|
|
||||||
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例子</p>
|
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ Package cryptor contains some functions for data encryption and decryption. Supp
|
|||||||
|
|
||||||
## Source:
|
## 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/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>
|
<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/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>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
|
|
||||||
@@ -186,7 +184,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="AesCtrCrypt">AesCtrCrypt</span>
|
### <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>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -132,12 +132,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="SinglyLink_InsertAt">InsertAt</span>
|
### <span id="SinglyLink_InsertAt">InsertAt</span>
|
||||||
<p>Insert value into singly linklist at index, index shoud be great or equal 0 and less or equal number of link nodes</p>
|
<p>Insert value into singly linklist at index, param `index` should between [0, len(SinglyLink)], if index do not meet the conditions, do nothing</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) InsertAt(index int, value T) error
|
func (link *SinglyLink[T]) InsertAt(index int, value T)
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -152,6 +152,8 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
lk := link.NewSinglyLink[int]()
|
lk := link.NewSinglyLink[int]()
|
||||||
|
|
||||||
|
lk.InsertAt(1, 1) //do nothing
|
||||||
|
|
||||||
lk.InsertAt(0, 1)
|
lk.InsertAt(0, 1)
|
||||||
lk.InsertAt(1, 2)
|
lk.InsertAt(1, 2)
|
||||||
lk.InsertAt(2, 3)
|
lk.InsertAt(2, 3)
|
||||||
@@ -228,12 +230,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="SinglyLink_DeleteAt">DeleteAt</span>
|
### <span id="SinglyLink_DeleteAt">DeleteAt</span>
|
||||||
<p>Delete value at specific index, index shoud be great or equal 0 and less or less than number of link nodes - 1</p>
|
<p>Delete value at specific index, param `index` should be [0, len(SinglyLink)-1]</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) DeleteAt(index int) error
|
func (link *SinglyLink[T]) DeleteAt(index int)
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -253,9 +255,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAt(3)
|
lk.DeleteAt(3)
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -268,7 +269,7 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) DeleteAtHead() error
|
func (link *SinglyLink[T]) DeleteAtHead()
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -288,9 +289,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAtHead()
|
lk.DeleteAtHead()
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -304,7 +304,7 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) DeleteAtTail() error
|
func (link *SinglyLink[T]) DeleteAtTail()
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -323,9 +323,8 @@ func main() {
|
|||||||
lk.InsertAtTail(2)
|
lk.InsertAtTail(2)
|
||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
|
|
||||||
err := lk.DeleteAtTail()
|
lk.DeleteAtTail()
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{1, 2}
|
fmt.Println(lk.Values()) //[]int{1, 2}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -628,12 +627,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="DoublyLink_InsertAt">InsertAt</span>
|
### <span id="DoublyLink_InsertAt">InsertAt</span>
|
||||||
<p>Insert value into doubly linklist at index, index shoud be great or equal 0 and less or equal number of link nodes</p>
|
<p>Insert value into doubly linklist at index, param `index` should between [0, len(DoublyLink)], if index do not meet the conditions, do nothing</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *DoublyLink[T]) InsertAt(index int, value T) error
|
func (link *DoublyLink[T]) InsertAt(index int, value T)
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -648,6 +647,8 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
lk := link.NewDoublyLink[int]()
|
lk := link.NewDoublyLink[int]()
|
||||||
|
|
||||||
|
lk.InsertAt(1, 1) //do nothing
|
||||||
|
|
||||||
lk.InsertAt(0, 1)
|
lk.InsertAt(0, 1)
|
||||||
lk.InsertAt(1, 2)
|
lk.InsertAt(1, 2)
|
||||||
lk.InsertAt(2, 3)
|
lk.InsertAt(2, 3)
|
||||||
@@ -724,12 +725,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="DoublyLink_DeleteAt">DeleteAt</span>
|
### <span id="DoublyLink_DeleteAt">DeleteAt</span>
|
||||||
<p>Delete value at specific index, index shoud be great or equal 0 and less or less than number of link nodes - 1</p>
|
<p>Delete value at specific index, param `index` should be [0, len(DoublyLink)-1]</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *DoublyLink[T]) DeleteAt(index int) error
|
func (link *DoublyLink[T]) DeleteAt(index int)
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -749,9 +750,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAt(3)
|
lk.DeleteAt(3)
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -764,7 +764,7 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *DoublyLink[T]) DeleteAtHead() error
|
func (link *DoublyLink[T]) DeleteAtHead()
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -784,9 +784,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAtHead()
|
lk.DeleteAtHead()
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -132,12 +132,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="SinglyLink_InsertAt">InsertAt</span>
|
### <span id="SinglyLink_InsertAt">InsertAt</span>
|
||||||
<p>将值插入到索引处的链表中,索引应大于或等于 0 且小于或等于链表节点数</p>
|
<p>将值插入到索引处的链表中,索引应大于或等于0且小于或等于链表节点数</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) InsertAt(index int, value T) error
|
func (link *SinglyLink[T]) InsertAt(index int, value T)
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -152,6 +152,8 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
lk := link.NewSinglyLink[int]()
|
lk := link.NewSinglyLink[int]()
|
||||||
|
|
||||||
|
lk.InsertAt(1, 1) //do nothing
|
||||||
|
|
||||||
lk.InsertAt(0, 1)
|
lk.InsertAt(0, 1)
|
||||||
lk.InsertAt(1, 2)
|
lk.InsertAt(1, 2)
|
||||||
lk.InsertAt(2, 3)
|
lk.InsertAt(2, 3)
|
||||||
@@ -228,12 +230,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="SinglyLink_DeleteAt">DeleteAt</span>
|
### <span id="SinglyLink_DeleteAt">DeleteAt</span>
|
||||||
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数 - 1</p>
|
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数-1</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) DeleteAt(index int) error
|
func (link *SinglyLink[T]) DeleteAt(index int)
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -253,9 +255,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAt(3)
|
lk.DeleteAt(3)
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -268,7 +269,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) DeleteAtHead() error
|
func (link *SinglyLink[T]) DeleteAtHead()
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -288,9 +289,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAtHead()
|
lk.DeleteAtHead()
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -304,7 +304,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *SinglyLink[T]) DeleteAtTail() error
|
func (link *SinglyLink[T]) DeleteAtTail()
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -323,9 +323,8 @@ func main() {
|
|||||||
lk.InsertAtTail(2)
|
lk.InsertAtTail(2)
|
||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
|
|
||||||
err := lk.DeleteAtTail()
|
lk.DeleteAtTail()
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{1, 2}
|
fmt.Println(lk.Values()) //[]int{1, 2}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -628,12 +627,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="DoublyLink_InsertAt">InsertAt</span>
|
### <span id="DoublyLink_InsertAt">InsertAt</span>
|
||||||
<p>将值插入到索引处的链表中,索引应大于或等于 0 且小于或等于链表节点数</p>
|
<p>将值插入到索引处的链表中,索引应大于或等于0且小于或等于链表节点数</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *DoublyLink[T]) InsertAt(index int, value T) error
|
func (link *DoublyLink[T]) InsertAt(index int, value T)
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -648,6 +647,8 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
lk := link.NewDoublyLink[int]()
|
lk := link.NewDoublyLink[int]()
|
||||||
|
|
||||||
|
lk.InsertAt(1, 1) //do nothing
|
||||||
|
|
||||||
lk.InsertAt(0, 1)
|
lk.InsertAt(0, 1)
|
||||||
lk.InsertAt(1, 2)
|
lk.InsertAt(1, 2)
|
||||||
lk.InsertAt(2, 3)
|
lk.InsertAt(2, 3)
|
||||||
@@ -724,12 +725,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="DoublyLink_DeleteAt">DeleteAt</span>
|
### <span id="DoublyLink_DeleteAt">DeleteAt</span>
|
||||||
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数 - 1</p>
|
<p>删除特定索引处的值,索引应大于或等于0且小于或等于链接节点数-1</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *DoublyLink[T]) DeleteAt(index int) error
|
func (link *DoublyLink[T]) DeleteAt(index int)
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -749,9 +750,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAt(3)
|
lk.DeleteAt(3)
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
fmt.Println(lk.Values()) //[]int{1, 2, 3}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -764,7 +764,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *DoublyLink[T]) DeleteAtHead() error
|
func (link *DoublyLink[T]) DeleteAtHead()
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -784,9 +784,8 @@ func main() {
|
|||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
lk.InsertAtTail(4)
|
lk.InsertAtTail(4)
|
||||||
|
|
||||||
err := lk.DeleteAtHead()
|
lk.DeleteAtHead()
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
fmt.Println(lk.Values()) //[]int{2, 3, 4}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -800,7 +799,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (link *DoublyLink[T]) DeleteAtTail() error
|
func (link *DoublyLink[T]) DeleteAtTail()
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -819,9 +818,8 @@ func main() {
|
|||||||
lk.InsertAtTail(2)
|
lk.InsertAtTail(2)
|
||||||
lk.InsertAtTail(3)
|
lk.InsertAtTail(3)
|
||||||
|
|
||||||
err := lk.DeleteAtTail()
|
lk.DeleteAtTail()
|
||||||
|
|
||||||
fmt.Println(err) //nil
|
|
||||||
fmt.Println(lk.Values()) //[]int{1, 2}
|
fmt.Println(lk.Values()) //[]int{1, 2}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -377,7 +377,7 @@ func main() {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### <span id="EndOfDay">EndOfDay</span>
|
### <span id="EndOfDay">EndOfDay</span>
|
||||||
<p>返回指定时间的当天结束时间.</p>
|
<p>返回指定时间的当天结束时间</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -541,7 +541,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="GetNowDateTime">GetNowDateTime</span>
|
### <span id="GetNowDateTime">GetNowDateTime</span>
|
||||||
<p>获取当时日期和时间,返回格式:yyyy-mm-dd hh:mm:ss.</p>
|
<p>获取当时日期和时间,返回格式:yyyy-mm-dd hh:mm:ss</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -568,7 +568,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span>
|
### <span id="GetZeroHourTimestamp">GetZeroHourTimestamp</span>
|
||||||
<p>获取零时时间戳(timestamp of 00:00).</p>
|
<p>获取零时时间戳(timestamp of 00:00)</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -595,7 +595,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="GetNightTimestamp">GetNightTimestamp</span>
|
### <span id="GetNightTimestamp">GetNightTimestamp</span>
|
||||||
<p>获取午夜时间戳(timestamp of 23:59).</p>
|
<p>获取午夜时间戳(timestamp of 23:59)</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="CopyFile">CopyFile</span>
|
### <span id="CopyFile">CopyFile</span>
|
||||||
<p>拷贝文件,会覆盖原有的拷贝文件</p>
|
<p>拷贝文件,会覆盖原有的文件</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="IsDir">IsDir</span>
|
### <span id="IsDir">IsDir</span>
|
||||||
<p>判断目录是否存在</p>
|
<p>判断参数是否是目录</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -28,13 +28,12 @@ import (
|
|||||||
|
|
||||||
|
|
||||||
### <span id="Comma">Comma</span>
|
### <span id="Comma">Comma</span>
|
||||||
<p>Add comma to number by every 3 numbers from right. ahead by symbol char.
|
<p>Add comma to a number value by every 3 numbers from right to left. ahead by symbol char. if value is a invalid number string like "aa", return empty string.</p>
|
||||||
Param should be number or numberic string.</p>
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Comma(v any, symbol string) string
|
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -28,12 +28,12 @@ import (
|
|||||||
|
|
||||||
|
|
||||||
### <span id="Comma">Comma</span>
|
### <span id="Comma">Comma</span>
|
||||||
<p>用逗号每隔3位分割数字/字符串,签名添加符号。参数必须是数字或者可以转为数字的字符串</p>
|
<p>用逗号每隔3位分割数字/字符串,支持前缀添加符号。参数value必须是数字或者可以转为数字的字符串, 否则返回空字符串</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Comma(v any, symbol string) string
|
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import (
|
|||||||
## Index
|
## Index
|
||||||
- [After](#After)
|
- [After](#After)
|
||||||
- [Before](#Before)
|
- [Before](#Before)
|
||||||
- [Curry](#Curry)
|
- [CurryFn](#CurryFn)
|
||||||
- [Compose](#Compose)
|
- [Compose](#Compose)
|
||||||
- [Debounced](#Debounced)
|
- [Debounced](#Debounced)
|
||||||
- [Delay](#Delay)
|
- [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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type Fn func(...any) any
|
type CurryFn[T any] func(...T) T
|
||||||
func (f Fn) Curry(i any) func(...any) any
|
func (cf CurryFn[T]) New(val T) func(...T) T
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -149,12 +149,15 @@ func main() {
|
|||||||
add := func(a, b int) int {
|
add := func(a, b int) int {
|
||||||
return a + b
|
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)
|
result := add1(2)
|
||||||
fmt.Println(result) //3
|
|
||||||
|
fmt.Println(result) //3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -167,7 +170,7 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Compose(fnList ...func(...any) any) func(...any) any
|
func Compose[T any](fnList ...func(...T) T) func(...T) T
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -180,17 +183,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
add1 := func(v ...any) any {
|
toUpper := func(strs ...string) string {
|
||||||
return v[0].(int) + 1
|
return strings.ToUpper(strs[0])
|
||||||
}
|
}
|
||||||
add2 := func(v ...any) any {
|
toLower := func(strs ...string) string {
|
||||||
return v[0].(int) + 2
|
return strings.ToLower(strs[0])
|
||||||
}
|
}
|
||||||
|
transform := Compose(toUpper, toLower)
|
||||||
|
|
||||||
add3 := function.Compose(add1, add2)
|
result := transform("aBCde")
|
||||||
result := add3(1)
|
|
||||||
|
|
||||||
fmt.Println(result) //4
|
fmt.Println(result) //ABCDE
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -259,9 +262,9 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var print = func(s string) {
|
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
|
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
|
stopTime int64
|
||||||
excuting bool
|
excuting bool
|
||||||
}
|
}
|
||||||
|
func NewWatcher() *Watcher
|
||||||
func (w *Watcher) Start() //start the watcher
|
func (w *Watcher) Start() //start the watcher
|
||||||
func (w *Watcher) Stop() //stop the watcher
|
func (w *Watcher) Stop() //stop the watcher
|
||||||
func (w *Watcher) Reset() //reset the watcher
|
func (w *Watcher) Reset() //reset the watcher
|
||||||
@@ -367,7 +371,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
w := &function.Watcher{}
|
w := function.NewWatcher()
|
||||||
|
|
||||||
w.Start()
|
w.Start()
|
||||||
|
|
||||||
longRunningTask()
|
longRunningTask()
|
||||||
@@ -377,14 +382,10 @@ func main() {
|
|||||||
w.Stop()
|
w.Stop()
|
||||||
|
|
||||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||||
|
|
||||||
fmt.Println(eapsedTime)
|
fmt.Println(eapsedTime)
|
||||||
|
|
||||||
w.Reset()
|
w.Reset()
|
||||||
|
|
||||||
fmt.Println(w.excuting) //false
|
|
||||||
|
|
||||||
fmt.Println(w.startTime) //0
|
|
||||||
fmt.Println(w.stopTime) //0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func longRunningTask() {
|
func longRunningTask() {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import (
|
|||||||
## 目录
|
## 目录
|
||||||
- [After](#After)
|
- [After](#After)
|
||||||
- [Before](#Before)
|
- [Before](#Before)
|
||||||
- [Curry](#Curry)
|
- [CurryFn](#CurryFn)
|
||||||
- [Compose](#Compose)
|
- [Compose](#Compose)
|
||||||
- [Debounced](#Debounced)
|
- [Debounced](#Debounced)
|
||||||
- [Delay](#Delay)
|
- [Delay](#Delay)
|
||||||
@@ -124,15 +124,15 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="Curry">Curry</span>
|
### <span id="CurryFn">CurryFn</span>
|
||||||
|
|
||||||
<p>创建一个柯里化的函数</p>
|
<p>创建柯里化函数</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type Fn func(...any) any
|
type CurryFn[T any] func(...T) T
|
||||||
func (f Fn) Curry(i any) func(...any) any
|
func (cf CurryFn[T]) New(val T) func(...T) T
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -148,11 +148,14 @@ func main() {
|
|||||||
add := func(a, b int) int {
|
add := func(a, b int) int {
|
||||||
return a + b
|
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)
|
result := add1(2)
|
||||||
|
|
||||||
fmt.Println(result) //3
|
fmt.Println(result) //3
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -161,12 +164,12 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Compose">Compose</span>
|
### <span id="Compose">Compose</span>
|
||||||
|
|
||||||
<p>从右至左组合函数列表fnList, 返回组合后的函数</p>
|
<p>从右至左组合函数列表fnList,返回组合后的函数</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Compose(fnList ...func(...any) any) func(...any) any
|
func Compose[T any](fnList ...func(...T) T) func(...T) T
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -179,17 +182,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
add1 := func(v ...any) any {
|
toUpper := func(strs ...string) string {
|
||||||
return v[0].(int) + 1
|
return strings.ToUpper(strs[0])
|
||||||
}
|
}
|
||||||
add2 := func(v ...any) any {
|
toLower := func(strs ...string) string {
|
||||||
return v[0].(int) + 2
|
return strings.ToLower(strs[0])
|
||||||
}
|
}
|
||||||
|
transform := Compose(toUpper, toLower)
|
||||||
|
|
||||||
add3 := function.Compose(add1, add2)
|
result := transform("aBCde")
|
||||||
result := add3(1)
|
|
||||||
|
|
||||||
fmt.Println(result) //4
|
fmt.Println(result) //ABCDE
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -197,7 +200,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Debounced">Debounced</span>
|
### <span id="Debounced">Debounced</span>
|
||||||
|
|
||||||
<p>创建一个 debounced 函数,该函数延迟调用 fn 直到自上次调用 debounced 函数后等待持续时间过去。</p>
|
<p>创建一个debounced函数,该函数延迟调用fn直到自上次调用debounced函数后等待持续时间过去。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -333,7 +336,7 @@ func main() {
|
|||||||
|
|
||||||
f := Pipeline(addOne, double, square)
|
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>
|
### <span id="Watcher">Watcher</span>
|
||||||
|
|
||||||
<p>Watcher 用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。 </p>
|
<p>Watcher用于记录代码执行时间。可以启动/停止/重置手表定时器。获取函数执行的时间。</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -351,6 +354,7 @@ type Watcher struct {
|
|||||||
stopTime int64
|
stopTime int64
|
||||||
excuting bool
|
excuting bool
|
||||||
}
|
}
|
||||||
|
func NewWatcher() *Watcher
|
||||||
func (w *Watcher) Start() //start the watcher
|
func (w *Watcher) Start() //start the watcher
|
||||||
func (w *Watcher) Stop() //stop the watcher
|
func (w *Watcher) Stop() //stop the watcher
|
||||||
func (w *Watcher) Reset() //reset the watcher
|
func (w *Watcher) Reset() //reset the watcher
|
||||||
@@ -367,7 +371,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
w := &function.Watcher{}
|
w := function.NewWatcher()
|
||||||
|
|
||||||
w.Start()
|
w.Start()
|
||||||
|
|
||||||
longRunningTask()
|
longRunningTask()
|
||||||
@@ -377,14 +382,11 @@ func main() {
|
|||||||
w.Stop()
|
w.Stop()
|
||||||
|
|
||||||
eapsedTime := w.GetElapsedTime().Milliseconds()
|
eapsedTime := w.GetElapsedTime().Milliseconds()
|
||||||
|
|
||||||
fmt.Println(eapsedTime)
|
fmt.Println(eapsedTime)
|
||||||
|
|
||||||
w.Reset()
|
w.Reset()
|
||||||
|
|
||||||
fmt.Println(w.excuting) //false
|
|
||||||
|
|
||||||
fmt.Println(w.startTime) //0
|
|
||||||
fmt.Println(w.stopTime) //0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func longRunningTask() {
|
func longRunningTask() {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import (
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Average[T lancetconstraints.Number](numbers ...T) T
|
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Max[T lancetconstraints.Number](numbers ...T) T
|
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -218,12 +218,12 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="Min">Min</span>
|
### <span id="Min">Min</span>
|
||||||
<p>Return min value of numbers.</p>
|
<p>Return the minimum value of numbers.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Min[T lancetconstraints.Number](numbers ...T) T
|
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||||
```
|
```
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|
||||||
@@ -302,8 +302,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
fmt.Println(mathutil.Percent(1, 2, 2)) //0.5
|
||||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //0.33
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ import (
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Average[T lancetconstraints.Number](numbers ...T) T
|
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Max[T lancetconstraints.Number](numbers ...T) T
|
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Min[T lancetconstraints.Number](numbers ...T) T
|
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
|
||||||
```
|
```
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
|
|
||||||
@@ -299,8 +299,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fmt.Println(mathutil.Percent(1, 2, 2)) //1
|
fmt.Println(mathutil.Percent(1, 2, 2)) //0.5
|
||||||
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
|
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //0.33
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -531,7 +531,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="StructToUrlValues">StructToUrlValues</span>
|
### <span id="StructToUrlValues">StructToUrlValues</span>
|
||||||
<p>将结构体转为url values, 仅转化结构体导出字段并且包含`json` tag.</p>
|
<p>将结构体转为url values, 仅转化结构体导出字段并且包含`json` tag</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -1138,7 +1138,7 @@ func main() {
|
|||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Sort[T lancetconstraints.Ordered](slice []T, sortOrder ...string)
|
func Sort[T constraints.Ordered](slice []T, sortOrder ...string)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>Example:</b>
|
<b>Example:</b>
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="DifferenceBy">DifferenceBy</span>
|
### <span id="DifferenceBy">DifferenceBy</span>
|
||||||
|
|
||||||
<p>在slice和comparedSlice中的每个元素调用iteratee函数,并比较它们的返回值,如果不想等返回在slice中对应的值</p>
|
<p>将两个slice中的每个元素调用iteratee函数,并比较它们的返回值,如果不相等返回在slice中对应的值</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -349,7 +349,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="DifferenceWith">DifferenceWith</span>
|
### <span id="DifferenceWith">DifferenceWith</span>
|
||||||
|
|
||||||
<p>DifferenceWith 接受比较器,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定</p>
|
<p>接受比较器函数,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -379,7 +379,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="DeleteAt">DeleteAt</span>
|
### <span id="DeleteAt">DeleteAt</span>
|
||||||
|
|
||||||
<p>删除切片中从开始索引到结束索引-1的元素</p>
|
<p>删除切片中指定开始索引到结束索引的元素</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -407,7 +407,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Drop">Drop</span>
|
### <span id="Drop">Drop</span>
|
||||||
|
|
||||||
<p>创建一个切片,当 n > 0 时从开头删除 n 个元素,或者当 n < 0 时从结尾删除 n 个元素</p>
|
<p>创建一个切片,当n > 0时从开头删除n个元素,或者当n < 0时从结尾删除n个元素</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -1135,7 +1135,7 @@ func main() {
|
|||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func Sort[T lancetconstraints.Ordered](slice []T, sortOrder ...string)
|
func Sort[T constraints.Ordered](slice []T, sortOrder ...string)
|
||||||
```
|
```
|
||||||
|
|
||||||
<b>例子:</b>
|
<b>例子:</b>
|
||||||
@@ -1442,7 +1442,7 @@ func main() {
|
|||||||
|
|
||||||
### <span id="Union">Union</span>
|
### <span id="Union">Union</span>
|
||||||
|
|
||||||
<p>合并多个切片.</p>
|
<p>合并多个切片</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
|||||||
165
docs/strutil.md
165
docs/strutil.md
@@ -28,13 +28,16 @@ import (
|
|||||||
- [Capitalize](#Capitalize)
|
- [Capitalize](#Capitalize)
|
||||||
- [IsString](#IsString)
|
- [IsString](#IsString)
|
||||||
- [KebabCase](#KebabCase)
|
- [KebabCase](#KebabCase)
|
||||||
|
- [UpperKebabCase](#UpperKebabCase)
|
||||||
- [LowerFirst](#LowerFirst)
|
- [LowerFirst](#LowerFirst)
|
||||||
- [UpperFirst](#UpperFirst)
|
- [UpperFirst](#UpperFirst)
|
||||||
- [PadEnd](#PadEnd)
|
- [PadEnd](#PadEnd)
|
||||||
- [PadStart](#PadStart)
|
- [PadStart](#PadStart)
|
||||||
- [Reverse](#Reverse)
|
- [Reverse](#Reverse)
|
||||||
- [SnakeCase](#SnakeCase)
|
- [SnakeCase](#SnakeCase)
|
||||||
|
- [UpperSnakeCase](#UpperSnakeCase)
|
||||||
- [SplitEx](#SplitEx)
|
- [SplitEx](#SplitEx)
|
||||||
|
- [Substring](#Substring)
|
||||||
- [Wrap](#Wrap)
|
- [Wrap](#Wrap)
|
||||||
- [Unwrap](#Unwrap)
|
- [Unwrap](#Unwrap)
|
||||||
|
|
||||||
@@ -45,7 +48,7 @@ import (
|
|||||||
|
|
||||||
|
|
||||||
### <span id="After">After</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -75,7 +78,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="AfterLast">AfterLast</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -106,7 +109,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="Before">Before</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -137,7 +140,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="BeforeLast">BeforeLast</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -165,10 +168,8 @@ func main() {
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="CamelCase">CamelCase</span>
|
### <span id="CamelCase">CamelCase</span>
|
||||||
<p>Covert string to camelCase string.</p>
|
<p>Coverts string to camelCase string, non letters and numbers will be ignored.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -195,6 +196,75 @@ func main() {
|
|||||||
|
|
||||||
s4 := strutil.CamelCase("foo bar")
|
s4 := strutil.CamelCase("foo bar")
|
||||||
fmt.Println(s4) //fooBar
|
fmt.Println(s4) //fooBar
|
||||||
|
|
||||||
|
s4 := strutil.CamelCase("Foo-#1😄$_%^&*(1bar")
|
||||||
|
fmt.Println(s4) //foo11Bar
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="KebabCase">KebabCase</span>
|
||||||
|
<p>KebabCase covert string to kebab-case, non letters and numbers will be ignored.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func KebabCase(s string) string
|
||||||
|
```
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s1 := strutil.KebabCase("Foo Bar-")
|
||||||
|
fmt.Println(s1) //foo-bar
|
||||||
|
|
||||||
|
s2 := strutil.KebabCase("foo_Bar")
|
||||||
|
fmt.Println(s2) //foo-bar
|
||||||
|
|
||||||
|
s3 := strutil.KebabCase("fooBar")
|
||||||
|
fmt.Println(s3) //foo-bar
|
||||||
|
|
||||||
|
s4 := strutil.KebabCase("__FOO_BAR__")
|
||||||
|
fmt.Println(s4) //foo-bar
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="UpperKebabCase">UpperKebabCase</span>
|
||||||
|
<p>UpperKebabCase covert string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func KebabCase(s string) string
|
||||||
|
```
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s1 := strutil.UpperKebabCase("Foo Bar-")
|
||||||
|
fmt.Println(s1) //FOO-BAR
|
||||||
|
|
||||||
|
s2 := strutil.UpperKebabCase("foo_Bar")
|
||||||
|
fmt.Println(s2) //FOO-BAR
|
||||||
|
|
||||||
|
s3 := strutil.UpperKebabCase("fooBar")
|
||||||
|
fmt.Println(s3) //FOO-BAR
|
||||||
|
|
||||||
|
s4 := strutil.UpperKebabCase("__FOO_BAR__")
|
||||||
|
fmt.Println(s4) //FOO-BAR
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -457,7 +527,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="SnakeCase">SnakeCase</span>
|
### <span id="SnakeCase">SnakeCase</span>
|
||||||
<p>Covert string to snake_case.</p>
|
<p>Coverts string to snake_case, non letters and numbers will be ignored.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -483,14 +553,47 @@ func main() {
|
|||||||
fmt.Println(s3) //foo_bar
|
fmt.Println(s3) //foo_bar
|
||||||
|
|
||||||
s4 := strutil.SnakeCase("__FOO_BAR__")
|
s4 := strutil.SnakeCase("__FOO_BAR__")
|
||||||
fmt.Println(s4) //f_o_o_b_a_r
|
fmt.Println(s4) //foo_bar
|
||||||
|
|
||||||
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
|
s5 := strutil.SnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||||
fmt.Println(s5) //a_bbc_s_a_b_b_c
|
fmt.Println(s5) //foo_1_1_bar
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="UpperSnakeCase">UpperSnakeCase</span>
|
||||||
|
<p>Coverts string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func SnakeCase(s string) string
|
||||||
|
```
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s1 := strutil.UpperSnakeCase("Foo Bar-")
|
||||||
|
fmt.Println(s1) //FOO_BAR
|
||||||
|
|
||||||
|
s2 := strutil.UpperSnakeCase("foo_Bar")
|
||||||
|
fmt.Println(s2) //FOO_BAR
|
||||||
|
|
||||||
|
s3 := strutil.UpperSnakeCase("fooBar")
|
||||||
|
fmt.Println(s3) //FOO_BAR
|
||||||
|
|
||||||
|
s4 := strutil.UpperSnakeCase("__FOO_BAR__")
|
||||||
|
fmt.Println(s4) //FOO_BAR
|
||||||
|
|
||||||
|
s5 := strutil.UpperSnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||||
|
fmt.Println(s5) //FOO_1_1_BAR
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### <span id="SplitEx">SplitEx</span>
|
### <span id="SplitEx">SplitEx</span>
|
||||||
@@ -529,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>
|
### <span id="Wrap">Wrap</span>
|
||||||
<p>Wrap a string with another string.</p>
|
<p>Wrap a string with given string.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -568,7 +707,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="Wrap">Wrap</span>
|
### <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>
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
|||||||
@@ -28,13 +28,16 @@ import (
|
|||||||
- [Capitalize](#Capitalize)
|
- [Capitalize](#Capitalize)
|
||||||
- [IsString](#IsString)
|
- [IsString](#IsString)
|
||||||
- [KebabCase](#KebabCase)
|
- [KebabCase](#KebabCase)
|
||||||
|
- [UpperKebabCase](#UpperKebabCase)
|
||||||
- [LowerFirst](#LowerFirst)
|
- [LowerFirst](#LowerFirst)
|
||||||
- [UpperFirst](#UpperFirst)
|
- [UpperFirst](#UpperFirst)
|
||||||
- [PadEnd](#PadEnd)
|
- [PadEnd](#PadEnd)
|
||||||
- [PadStart](#PadStart)
|
- [PadStart](#PadStart)
|
||||||
- [Reverse](#Reverse)
|
- [Reverse](#Reverse)
|
||||||
- [SnakeCase](#SnakeCase)
|
- [SnakeCase](#SnakeCase)
|
||||||
|
- [UpperSnakeCase](#UpperSnakeCase)
|
||||||
- [SplitEx](#SplitEx)
|
- [SplitEx](#SplitEx)
|
||||||
|
- [Substring](#Substring)
|
||||||
- [Wrap](#Wrap)
|
- [Wrap](#Wrap)
|
||||||
- [Unwrap](#Unwrap)
|
- [Unwrap](#Unwrap)
|
||||||
|
|
||||||
@@ -46,7 +49,7 @@ import (
|
|||||||
|
|
||||||
|
|
||||||
### <span id="After">After</span>
|
### <span id="After">After</span>
|
||||||
<p>截取源字符串中char首次出现时的位置之后的子字符串</p>
|
<p>返回源字符串中特定字符串首次出现时的位置之后的子字符串</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -76,7 +79,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="AfterLast">AfterLast</span>
|
### <span id="AfterLast">AfterLast</span>
|
||||||
<p>截取源字符串中char最后一次出现时的位置之后的子字符串</p>
|
<p>返回源字符串中指定字符串最后一次出现时的位置之后的子字符串</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -107,7 +110,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="Before">Before</span>
|
### <span id="Before">Before</span>
|
||||||
<p>截取源字符串中char首次出现时的位置之前的子字符串</p>
|
<p>返回源字符串中指定字符串第一次出现时的位置之前的子字符串</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -138,7 +141,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="BeforeLast">BeforeLast</span>
|
### <span id="BeforeLast">BeforeLast</span>
|
||||||
<p>截取源字符串中char最后一次出现时的位置之前的子字符串</p>
|
<p>返回源字符串中指定字符串最后一次出现时的位置之前的子字符串</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -169,7 +172,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="CamelCase">CamelCase</span>
|
### <span id="CamelCase">CamelCase</span>
|
||||||
<p>将字符串转换为驼峰式字符串</p>
|
<p>将字符串转换为驼峰式字符串, 非字母和数字会被忽略</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -196,6 +199,9 @@ func main() {
|
|||||||
|
|
||||||
s4 := strutil.CamelCase("foo bar")
|
s4 := strutil.CamelCase("foo bar")
|
||||||
fmt.Println(s4) //fooBar
|
fmt.Println(s4) //fooBar
|
||||||
|
|
||||||
|
s4 := strutil.CamelCase("Foo-#1😄$_%^&*(1bar")
|
||||||
|
fmt.Println(s4) //foo11Bar
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -233,7 +239,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="IsString">IsString</span>
|
### <span id="IsString">IsString</span>
|
||||||
<p>检查值的数据类型是否为字符串</p>
|
<p>判断传入参数的数据类型是否为字符串</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -261,7 +267,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="KebabCase">KebabCase</span>
|
### <span id="KebabCase">KebabCase</span>
|
||||||
<p>将字符串转换为kebab-case</p>
|
<p>将字符串转换为kebab-case, 非字母和数字会被忽略</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -287,7 +293,40 @@ func main() {
|
|||||||
fmt.Println(s3) //foo-bar
|
fmt.Println(s3) //foo-bar
|
||||||
|
|
||||||
s4 := strutil.KebabCase("__FOO_BAR__")
|
s4 := strutil.KebabCase("__FOO_BAR__")
|
||||||
fmt.Println(s4) //f-o-o-b-a-r
|
fmt.Println(s4) //foo-bar
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="UpperKebabCase">UpperKebabCase</span>
|
||||||
|
<p>将字符串转换为大写KEBAB-CASE, 非字母和数字会被忽略</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func KebabCase(s string) string
|
||||||
|
```
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s1 := strutil.UpperKebabCase("Foo Bar-")
|
||||||
|
fmt.Println(s1) //FOO-BAR
|
||||||
|
|
||||||
|
s2 := strutil.UpperKebabCase("foo_Bar")
|
||||||
|
fmt.Println(s2) //FOO-BAR
|
||||||
|
|
||||||
|
s3 := strutil.UpperKebabCase("fooBar")
|
||||||
|
fmt.Println(s3) //FOO-BAR
|
||||||
|
|
||||||
|
s4 := strutil.UpperKebabCase("__FOO_BAR__")
|
||||||
|
fmt.Println(s4) //FOO-BAR
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -329,7 +368,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="UpperFirst">UpperFirst</span>
|
### <span id="UpperFirst">UpperFirst</span>
|
||||||
<p>将字符串的第一个字符转换为大写</p>
|
<p>将字符串的第一个字符转换为大写形式</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -458,7 +497,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="SnakeCase">SnakeCase</span>
|
### <span id="SnakeCase">SnakeCase</span>
|
||||||
<p>将字符串转换为snake_case形式</p>
|
<p>将字符串转换为snake_case形式, 非字母和数字会被忽略</p>
|
||||||
|
|
||||||
<b>函数签名:</b>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -484,10 +523,45 @@ func main() {
|
|||||||
fmt.Println(s3) //foo_bar
|
fmt.Println(s3) //foo_bar
|
||||||
|
|
||||||
s4 := strutil.SnakeCase("__FOO_BAR__")
|
s4 := strutil.SnakeCase("__FOO_BAR__")
|
||||||
fmt.Println(s4) //f_o_o_b_a_r
|
fmt.Println(s4) //foo_bar
|
||||||
|
|
||||||
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
|
s5 := strutil.SnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||||
fmt.Println(s5) //a_bbc_s_a_b_b_c
|
fmt.Println(s5) //foo_1_1_bar
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="UpperSnakeCase">UpperSnakeCase</span>
|
||||||
|
<p>将字符串转换为大写SNAKE_CASE形式, 非字母和数字会被忽略</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func SnakeCase(s string) string
|
||||||
|
```
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/strutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
s1 := strutil.UpperSnakeCase("Foo Bar-")
|
||||||
|
fmt.Println(s1) //FOO_BAR
|
||||||
|
|
||||||
|
s2 := strutil.UpperSnakeCase("foo_Bar")
|
||||||
|
fmt.Println(s2) //FOO_BAR
|
||||||
|
|
||||||
|
s3 := strutil.UpperSnakeCase("fooBar")
|
||||||
|
fmt.Println(s3) //FOO_BAR
|
||||||
|
|
||||||
|
s4 := strutil.UpperSnakeCase("__FOO_BAR__")
|
||||||
|
fmt.Println(s4) //FOO_BAR
|
||||||
|
|
||||||
|
s5 := strutil.UpperSnakeCase("Foo-#1😄$_%^&*(1bar")
|
||||||
|
fmt.Println(s5) //FOO_1_1_BAR
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -527,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>
|
### <span id="Wrap">Wrap</span>
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
isOsMac := system.IsMac
|
isOsMac := system.IsMac()
|
||||||
fmt.Println(isOsMac)
|
fmt.Println(isOsMac)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -211,7 +211,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="ExecCommand">CompareOsEnv</span>
|
### <span id="ExecCommand">CompareOsEnv</span>
|
||||||
<p>Use shell /bin/bash -c(linux) or cmd (windows) to execute command.</p>
|
<p>Execute shell command, return the stdout and stderr string of command, and error if error occur. 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.</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -227,10 +227,24 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
out, errout, err := system.ExecCommand("ls")
|
// linux or mac
|
||||||
fmt.Println(out)
|
stdout, stderr, err := system.ExecCommand("ls")
|
||||||
fmt.Println(errout)
|
fmt.Println("std out: ", stdout)
|
||||||
fmt.Println(err)
|
fmt.Println("std err: ", stderr)
|
||||||
|
assert.Equal("", stderr)
|
||||||
|
|
||||||
|
// windows
|
||||||
|
stdout, stderr, err = system.ExecCommand("dir")
|
||||||
|
fmt.Println("std out: ", stdout)
|
||||||
|
fmt.Println("std err: ", stderr)
|
||||||
|
|
||||||
|
// error command
|
||||||
|
stdout, stderr, err = system.ExecCommand("abc")
|
||||||
|
fmt.Println("std out: ", stdout)
|
||||||
|
fmt.Println("std err: ", stderr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ import (
|
|||||||
- [GetOsEnv](#GetOsEnv)
|
- [GetOsEnv](#GetOsEnv)
|
||||||
- [SetOsEnv](#SetOsEnv)
|
- [SetOsEnv](#SetOsEnv)
|
||||||
- [RemoveOsEnv](#RemoveOsEnv)
|
- [RemoveOsEnv](#RemoveOsEnv)
|
||||||
|
|
||||||
- [CompareOsEnv](#CompareOsEnv)
|
- [CompareOsEnv](#CompareOsEnv)
|
||||||
- [ExecCommand](#ExecCommand)
|
- [ExecCommand](#ExecCommand)
|
||||||
- [GetOsBits](#GetOsBits)
|
- [GetOsBits](#GetOsBits)
|
||||||
@@ -103,7 +102,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
isOsMac := system.IsMac
|
isOsMac := system.IsMac()
|
||||||
fmt.Println(isOsMac)
|
fmt.Println(isOsMac)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -212,7 +211,7 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
### <span id="ExecCommand">ExecCommand</span>
|
### <span id="ExecCommand">ExecCommand</span>
|
||||||
<p>使用shell /bin/bash -c(linux) 或 cmd (windows) 执行shell命令</p>
|
<p>执行shell命令,返回命令的stdout和stderr字符串,如果出现错误,则返回错误。参数`command`是一个完整的命令字符串,如ls-a(linux),dir(windows),ping 127.0.0.1。在linux中,使用/bin/bash-c执行命令,在windows中,使用powershell.exe执行命令。</p>
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
@@ -228,10 +227,24 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
out, errout, err := system.ExecCommand("ls")
|
// linux or mac
|
||||||
fmt.Println(out)
|
stdout, stderr, err := system.ExecCommand("ls")
|
||||||
fmt.Println(errout)
|
fmt.Println("std out: ", stdout)
|
||||||
fmt.Println(err)
|
fmt.Println("std err: ", stderr)
|
||||||
|
assert.Equal("", stderr)
|
||||||
|
|
||||||
|
// windows
|
||||||
|
stdout, stderr, err = system.ExecCommand("dir")
|
||||||
|
fmt.Println("std out: ", stdout)
|
||||||
|
fmt.Println("std err: ", stderr)
|
||||||
|
|
||||||
|
// error command
|
||||||
|
stdout, stderr, err = system.ExecCommand("abc")
|
||||||
|
fmt.Println("std out: ", stdout)
|
||||||
|
fmt.Println("std err: ", stderr)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import (
|
|||||||
- [IsUrl](#IsUrl)
|
- [IsUrl](#IsUrl)
|
||||||
- [IsWeakPassword](#IsWeakPassword)
|
- [IsWeakPassword](#IsWeakPassword)
|
||||||
- [IsZeroValue](#IsZeroValue)
|
- [IsZeroValue](#IsZeroValue)
|
||||||
|
- [IsGBK](#IsGBK)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -821,7 +822,34 @@ func main() {
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### <span id="IsGBK">IsGBK</span>
|
||||||
|
<p>Checks if data encoding is gbk(Chinese character internal code extension specification). this function is implemented by whether double bytes fall within the encoding range of gbk,while each byte of utf-8 encoding format falls within the encoding range of gbk.Therefore, utf8.valid() should be called first to check whether it is not utf-8 encoding and then call IsGBK() to check gbk encoding. like the example.</p>
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsGBK(data []byte) bool
|
||||||
|
```
|
||||||
|
<b>Example:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
data := []byte("你好")
|
||||||
|
|
||||||
|
// check utf8 first
|
||||||
|
if utf8.Valid(data) {
|
||||||
|
fmt.Println("data encoding is utf-8")
|
||||||
|
}else if(validator.IsGBK(data)) {
|
||||||
|
fmt.Println("data encoding is GBK")
|
||||||
|
}
|
||||||
|
fmt.Println("data encoding is unknown")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import (
|
|||||||
- [IsUrl](#IsUrl)
|
- [IsUrl](#IsUrl)
|
||||||
- [IsWeakPassword](#IsWeakPassword)
|
- [IsWeakPassword](#IsWeakPassword)
|
||||||
- [IsZeroValue](#IsZeroValue)
|
- [IsZeroValue](#IsZeroValue)
|
||||||
|
- [IsGBK](#IsGBK)
|
||||||
|
|
||||||
|
|
||||||
<div STYLE="page-break-after: always;"></div>
|
<div STYLE="page-break-after: always;"></div>
|
||||||
@@ -458,8 +459,6 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsEmptyString">IsEmptyString</span>
|
### <span id="IsEmptyString">IsEmptyString</span>
|
||||||
<p>验证字符串是否是空字符串</p>
|
<p>验证字符串是否是空字符串</p>
|
||||||
|
|
||||||
@@ -487,7 +486,6 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsFloatStr">IsFloatStr</span>
|
### <span id="IsFloatStr">IsFloatStr</span>
|
||||||
<p>验证字符串是否是可以转换为浮点数</p>
|
<p>验证字符串是否是可以转换为浮点数</p>
|
||||||
|
|
||||||
@@ -573,8 +571,6 @@ func main() {
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsRegexMatch">IsRegexMatch</span>
|
### <span id="IsRegexMatch">IsRegexMatch</span>
|
||||||
<p>验证字符串是否可以匹配正则表达式</p>
|
<p>验证字符串是否可以匹配正则表达式</p>
|
||||||
|
|
||||||
@@ -600,7 +596,6 @@ func main() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### <span id="IsIntStr">IsIntStr</span>
|
### <span id="IsIntStr">IsIntStr</span>
|
||||||
<p>验证字符串是否是可以转换为整数</p>
|
<p>验证字符串是否是可以转换为整数</p>
|
||||||
|
|
||||||
@@ -820,3 +815,31 @@ func main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### <span id="IsGBK">IsGBK</span>
|
||||||
|
<p>检查数据编码是否为gbk(汉字内部代码扩展规范)。该函数的实现取决于双字节是否在gbk的编码范围内,而utf-8编码格式的每个字节都在gbk编码范围内。因此,应该首先调用utf8.valid检查它是否是utf-8编码,然后调用IsGBK检查gbk编码。如示例所示。</p>
|
||||||
|
|
||||||
|
<b>函数签名:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
func IsGBK(data []byte) bool
|
||||||
|
```
|
||||||
|
<b>例子:</b>
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/duke-git/lancet/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
data := []byte("你好")
|
||||||
|
|
||||||
|
// 先检查utf8编码
|
||||||
|
if utf8.Valid(data) {
|
||||||
|
fmt.Println("data encoding is utf-8")
|
||||||
|
}else if(validator.IsGBK(data)) {
|
||||||
|
fmt.Println("data encoding is GBK")
|
||||||
|
}
|
||||||
|
fmt.Println("data encoding is unknown")
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -46,12 +46,20 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
result1 := xerror.Unwrap(strconv.Atoi("42"))
|
||||||
|
fmt.Println(result1)
|
||||||
|
|
||||||
_, err := strconv.Atoi("4o2")
|
_, err := strconv.Atoi("4o2")
|
||||||
defer func() {
|
defer func() {
|
||||||
v := recover()
|
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"))
|
xerror.Unwrap(strconv.Atoi("4o2"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 42
|
||||||
|
// true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import (
|
|||||||
|
|
||||||
|
|
||||||
### <span id="Unwrap">Unwrap</span>
|
### <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>
|
<b>函数签名:</b>
|
||||||
|
|
||||||
@@ -46,12 +46,20 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
result1 := xerror.Unwrap(strconv.Atoi("42"))
|
||||||
|
fmt.Println(result1)
|
||||||
|
|
||||||
_, err := strconv.Atoi("4o2")
|
_, err := strconv.Atoi("4o2")
|
||||||
defer func() {
|
defer func() {
|
||||||
v := recover()
|
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"))
|
xerror.Unwrap(strconv.Atoi("4o2"))
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// 42
|
||||||
|
// true
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@@ -19,7 +18,8 @@ import (
|
|||||||
"strings"
|
"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 {
|
func IsExist(path string) bool {
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -31,7 +31,8 @@ func IsExist(path string) bool {
|
|||||||
return false
|
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 {
|
func CreateFile(path string) bool {
|
||||||
file, err := os.Create(path)
|
file, err := os.Create(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -42,12 +43,14 @@ func CreateFile(path string) bool {
|
|||||||
return true
|
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 {
|
func CreateDir(absPath string) error {
|
||||||
return os.MkdirAll(path.Dir(absPath), os.ModePerm)
|
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 {
|
func IsDir(path string) bool {
|
||||||
file, err := os.Stat(path)
|
file, err := os.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -56,12 +59,14 @@ func IsDir(path string) bool {
|
|||||||
return file.IsDir()
|
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 {
|
func RemoveFile(path string) error {
|
||||||
return os.Remove(path)
|
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 {
|
func CopyFile(srcFilePath string, dstFilePath string) error {
|
||||||
srcFile, err := os.Open(srcFilePath)
|
srcFile, err := os.Open(srcFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -78,17 +83,21 @@ func CopyFile(srcFilePath string, dstFilePath string) error {
|
|||||||
var tmp = make([]byte, 1024*4)
|
var tmp = make([]byte, 1024*4)
|
||||||
for {
|
for {
|
||||||
n, err := srcFile.Read(tmp)
|
n, err := srcFile.Read(tmp)
|
||||||
distFile.Write(tmp[:n])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
_, err = distFile.Write(tmp[:n])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//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 {
|
func ClearFile(path string) error {
|
||||||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -100,16 +109,18 @@ func ClearFile(path string) error {
|
|||||||
return err
|
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) {
|
func ReadFileToString(path string) (string, error) {
|
||||||
bytes, err := ioutil.ReadFile(path)
|
bytes, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return string(bytes), nil
|
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) {
|
func ReadFileByLine(path string) ([]string, error) {
|
||||||
f, err := os.Open(path)
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -135,13 +146,14 @@ func ReadFileByLine(path string) ([]string, error) {
|
|||||||
return result, nil
|
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) {
|
func ListFileNames(path string) ([]string, error) {
|
||||||
if !IsExist(path) {
|
if !IsExist(path) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fs, err := ioutil.ReadDir(path)
|
fs, err := os.ReadDir(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []string{}, err
|
return []string{}, err
|
||||||
}
|
}
|
||||||
@@ -161,7 +173,8 @@ func ListFileNames(path string) ([]string, error) {
|
|||||||
return result, nil
|
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 {
|
func Zip(fpath string, destPath string) error {
|
||||||
zipFile, err := os.Create(destPath)
|
zipFile, err := os.Create(destPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -172,7 +185,7 @@ func Zip(fpath string, destPath string) error {
|
|||||||
archive := zip.NewWriter(zipFile)
|
archive := zip.NewWriter(zipFile)
|
||||||
defer archive.Close()
|
defer archive.Close()
|
||||||
|
|
||||||
filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
err = filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -209,10 +222,15 @@ func Zip(fpath string, destPath string) error {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
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 {
|
func UnZip(zipFile string, destPath string) error {
|
||||||
|
|
||||||
zipReader, err := zip.OpenReader(zipFile)
|
zipReader, err := zip.OpenReader(zipFile)
|
||||||
@@ -229,9 +247,13 @@ func UnZip(zipFile string, destPath string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if f.FileInfo().IsDir() {
|
if f.FileInfo().IsDir() {
|
||||||
os.MkdirAll(path, os.ModePerm)
|
err = os.MkdirAll(path, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if err = os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
|
err = os.MkdirAll(filepath.Dir(path), os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,7 +289,8 @@ func safeFilepathJoin(path1, path2 string) (string, error) {
|
|||||||
return filepath.Join(path1, filepath.Join("/", relPath)), nil
|
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 {
|
func IsLink(path string) bool {
|
||||||
fi, err := os.Lstat(path)
|
fi, err := os.Lstat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -276,7 +299,8 @@ func IsLink(path string) bool {
|
|||||||
return fi.Mode()&os.ModeSymlink != 0
|
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) {
|
func FileMode(path string) (fs.FileMode, error) {
|
||||||
fi, err := os.Lstat(path)
|
fi, err := os.Lstat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -286,7 +310,8 @@ func FileMode(path string) (fs.FileMode, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MiMeType return file mime type
|
// 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 {
|
func MiMeType(file any) string {
|
||||||
var mediatype 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
|
||||||
|
}
|
||||||
@@ -25,9 +25,10 @@ func TestCreateFile(t *testing.T) {
|
|||||||
f := "./text.txt"
|
f := "./text.txt"
|
||||||
if CreateFile(f) {
|
if CreateFile(f) {
|
||||||
file, err := os.Open(f)
|
file, err := os.Open(f)
|
||||||
defer file.Close()
|
|
||||||
assert.IsNil(err)
|
assert.IsNil(err)
|
||||||
assert.Equal(f, file.Name())
|
assert.Equal(f, file.Name())
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
} else {
|
} else {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
@@ -95,16 +96,6 @@ func TestCopyFile(t *testing.T) {
|
|||||||
os.Remove(destFile)
|
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) {
|
func TestReadFileToString(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestReadFileToString")
|
assert := internal.NewAssert(t, "TestReadFileToString")
|
||||||
|
|
||||||
@@ -113,7 +104,11 @@ func TestReadFileToString(t *testing.T) {
|
|||||||
|
|
||||||
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
f.WriteString("hello world")
|
|
||||||
|
_, err := f.WriteString("hello world")
|
||||||
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
|
||||||
content, _ := ReadFileToString(path)
|
content, _ := ReadFileToString(path)
|
||||||
assert.Equal("hello world", content)
|
assert.Equal("hello world", content)
|
||||||
@@ -130,9 +125,12 @@ func TestClearFile(t *testing.T) {
|
|||||||
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
f.WriteString("hello world")
|
_, err := f.WriteString("hello world")
|
||||||
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
|
||||||
err := ClearFile(path)
|
err = ClearFile(path)
|
||||||
assert.IsNil(err)
|
assert.IsNil(err)
|
||||||
|
|
||||||
content, _ := ReadFileToString(path)
|
content, _ := ReadFileToString(path)
|
||||||
@@ -148,8 +146,13 @@ func TestReadFileByLine(t *testing.T) {
|
|||||||
CreateFile(path)
|
CreateFile(path)
|
||||||
|
|
||||||
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
|
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
f.WriteString("hello\nworld")
|
|
||||||
|
_, err := f.WriteString("hello\nworld")
|
||||||
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
}
|
||||||
|
|
||||||
expected := []string{"hello", "world"}
|
expected := []string{"hello", "world"}
|
||||||
actual, _ := ReadFileByLine(path)
|
actual, _ := ReadFileByLine(path)
|
||||||
@@ -166,10 +169,14 @@ func TestZipAndUnZip(t *testing.T) {
|
|||||||
|
|
||||||
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, 0777)
|
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, 0777)
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
file.WriteString("hello\nworld")
|
|
||||||
|
_, err := file.WriteString("hello\nworld")
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
zipFile := "./text.zip"
|
zipFile := "./text.zip"
|
||||||
err := Zip(srcFile, zipFile)
|
err = Zip(srcFile, zipFile)
|
||||||
assert.IsNil(err)
|
assert.IsNil(err)
|
||||||
|
|
||||||
unZipPath := "./unzip"
|
unZipPath := "./unzip"
|
||||||
@@ -224,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(f))
|
||||||
assert.Equal("text/plain; charset=utf-8", MiMeType("./file.go"))
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,14 +4,68 @@
|
|||||||
// Package formatter implements some functions to format string, struct.
|
// Package formatter implements some functions to format string, struct.
|
||||||
package formatter
|
package formatter
|
||||||
|
|
||||||
import "strings"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// Comma add comma to number by every 3 numbers from right. ahead by symbol char
|
|
||||||
func Comma(v any, symbol string) string {
|
|
||||||
s := numString(v)
|
|
||||||
dotIndex := strings.Index(s, ".")
|
dotIndex := strings.Index(s, ".")
|
||||||
if dotIndex != -1 {
|
if dotIndex != -1 {
|
||||||
return symbol + commaString(s[:dotIndex]) + s[dotIndex:]
|
return symbol + commaString(s[:dotIndex]) + s[dotIndex:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return symbol + commaString(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,40 +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 numString(value any) string {
|
|
||||||
switch reflect.TypeOf(value).Kind() {
|
|
||||||
case reflect.Int, reflect.Int64, reflect.Float32, reflect.Float64:
|
|
||||||
return fmt.Sprintf("%v", value)
|
|
||||||
case reflect.String:
|
|
||||||
{
|
|
||||||
sv := fmt.Sprintf("%v", value)
|
|
||||||
if strings.Contains(sv, ".") {
|
|
||||||
_, err := strconv.ParseFloat(sv, 64)
|
|
||||||
if err == nil {
|
|
||||||
return sv
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_, err := strconv.ParseInt(sv, 10, 64)
|
|
||||||
if err == nil {
|
|
||||||
return sv
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
@@ -12,12 +12,16 @@ func TestComma(t *testing.T) {
|
|||||||
assert.Equal("", Comma("", ""))
|
assert.Equal("", Comma("", ""))
|
||||||
assert.Equal("", Comma("aa", ""))
|
assert.Equal("", Comma("aa", ""))
|
||||||
assert.Equal("", Comma("aa.a", ""))
|
assert.Equal("", Comma("aa.a", ""))
|
||||||
assert.Equal("", Comma([]int{1}, ""))
|
|
||||||
assert.Equal("123", Comma("123", ""))
|
assert.Equal("123", Comma("123", ""))
|
||||||
assert.Equal("12,345", Comma("12345", ""))
|
assert.Equal("12,345", Comma("12345", ""))
|
||||||
|
assert.Equal("12,345.6789", Comma("12345.6789", ""))
|
||||||
|
assert.Equal("123,456,789,000", Comma("123456789000", ""))
|
||||||
|
|
||||||
assert.Equal("12,345", Comma(12345, ""))
|
assert.Equal("12,345", Comma(12345, ""))
|
||||||
assert.Equal("$12,345", Comma(12345, "$"))
|
assert.Equal("$12,345", Comma(12345, "$"))
|
||||||
assert.Equal("¥12,345", Comma(12345, "¥"))
|
assert.Equal("¥12,345", Comma(12345, "¥"))
|
||||||
assert.Equal("12,345.6789", Comma(12345.6789, ""))
|
assert.Equal("12,345.6789", Comma(12345.6789, ""))
|
||||||
|
assert.Equal("12,345.6789", Comma(+12345.6789, ""))
|
||||||
|
// assert.Equal("12,345,678.9", Comma(12345678.9, ""))
|
||||||
|
assert.Equal("123,456,789,000", Comma(123456789000, ""))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,13 @@
|
|||||||
package function
|
package function
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"time"
|
"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 {
|
func After(n int, fn any) func(args ...any) []reflect.Value {
|
||||||
// Catch programming error while constructing the closure
|
// Catch programming error while constructing the closure
|
||||||
mustBeFunction(fn)
|
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 {
|
func Before(n int, fn any) func(args ...any) []reflect.Value {
|
||||||
// Catch programming error while constructing the closure
|
// Catch programming error while constructing the closure
|
||||||
mustBeFunction(fn)
|
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
|
// CurryFn is for make curry function
|
||||||
type Fn func(...any) any
|
type CurryFn[T any] func(...T) T
|
||||||
|
|
||||||
// Curry make a curry function
|
// New make a curry function for specific value.
|
||||||
func (f Fn) Curry(i any) func(...any) any {
|
// Play: Todo
|
||||||
return func(values ...any) any {
|
func (cf CurryFn[T]) New(val T) func(...T) T {
|
||||||
v := append([]any{i}, values...)
|
return func(vals ...T) T {
|
||||||
return f(v...)
|
args := append([]T{val}, vals...)
|
||||||
|
return cf(args...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compose compose the functions from right to left
|
// Compose compose the functions from right to left.
|
||||||
func Compose(fnList ...func(...any) any) func(...any) any {
|
// Play: Todo
|
||||||
return func(s ...any) any {
|
func Compose[T any](fnList ...func(...T) T) func(...T) T {
|
||||||
f := fnList[0]
|
return func(args ...T) T {
|
||||||
restFn := fnList[1:]
|
firstFn := fnList[0]
|
||||||
|
restFns := fnList[1:]
|
||||||
|
|
||||||
if len(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) {
|
func Delay(delay time.Duration, fn any, args ...any) {
|
||||||
// Catch programming error while constructing the closure
|
// Catch programming error while constructing the closure
|
||||||
mustBeFunction(fn)
|
mustBeFunction(fn)
|
||||||
|
|
||||||
time.Sleep(delay)
|
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.
|
// 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() {
|
func Debounced(fn func(), duration time.Duration) func() {
|
||||||
// Catch programming error while constructing the closure
|
// Catch programming error while constructing the closure
|
||||||
mustBeFunction(fn)
|
mustBeFunction(fn)
|
||||||
@@ -84,17 +94,16 @@ func Debounced(fn func(), duration time.Duration) func() {
|
|||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
<-timer.C
|
||||||
case <-timer.C:
|
go fn()
|
||||||
go fn()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return func() { timer.Reset(duration) }
|
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 {
|
func Schedule(d time.Duration, fn any, args ...any) chan bool {
|
||||||
// Catch programming error while constructing the closure
|
// Catch programming error while constructing the closure
|
||||||
mustBeFunction(fn)
|
mustBeFunction(fn)
|
||||||
@@ -116,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
|
// Pipeline takes a list of functions and returns a function whose param will be passed into
|
||||||
// the functions one by one.
|
// the functions one by one.
|
||||||
|
// Play: https://go.dev/play/p/mPdUVvj6HD6
|
||||||
func Pipeline[T any](funcs ...func(T) T) func(T) T {
|
func Pipeline[T any](funcs ...func(T) T) func(T) T {
|
||||||
return func(arg T) (result T) {
|
return func(arg T) (result T) {
|
||||||
result = arg
|
result = arg
|
||||||
@@ -125,3 +135,19 @@ func Pipeline[T any](funcs ...func(T) T) func(T) T {
|
|||||||
return
|
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 {
|
add := func(a, b int) int {
|
||||||
return a + b
|
return a + b
|
||||||
}
|
}
|
||||||
var addCurry Fn = func(values ...any) any {
|
var addCurry CurryFn[int] = func(values ...int) int {
|
||||||
return add(values[0].(int), values[1].(int))
|
return add(values[0], values[1])
|
||||||
}
|
}
|
||||||
add1 := addCurry.Curry(1)
|
add1 := addCurry.New(1)
|
||||||
|
|
||||||
assert.Equal(3, add1(2))
|
assert.Equal(3, add1(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompose(t *testing.T) {
|
func TestCompose(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestCompose")
|
assert := internal.NewAssert(t, "TestCompose")
|
||||||
|
|
||||||
toUpper := func(a ...any) any {
|
toUpper := func(strs ...string) string {
|
||||||
return strings.ToUpper(a[0].(string))
|
return strings.ToUpper(strs[0])
|
||||||
}
|
}
|
||||||
toLower := func(a ...any) any {
|
toLower := func(strs ...string) string {
|
||||||
return strings.ToLower(a[0].(string))
|
return strings.ToLower(strs[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := toUpper(toLower("aBCde"))
|
expected := toUpper(toLower("aBCde"))
|
||||||
|
|
||||||
cf := Compose(toUpper, toLower)
|
cf := Compose(toUpper, toLower)
|
||||||
res := cf("aBCde")
|
res := cf("aBCde")
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,18 @@ package function
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
// Watcher is used for record code excution time
|
// Watcher is used for record code excution time
|
||||||
|
// Play: Todo
|
||||||
type Watcher struct {
|
type Watcher struct {
|
||||||
startTime int64
|
startTime int64
|
||||||
stopTime int64
|
stopTime int64
|
||||||
excuting bool
|
excuting bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start the watch timer.
|
||||||
|
func NewWatcher() *Watcher {
|
||||||
|
return &Watcher{}
|
||||||
|
}
|
||||||
|
|
||||||
// Start the watch timer.
|
// Start the watch timer.
|
||||||
func (w *Watcher) Start() {
|
func (w *Watcher) Start() {
|
||||||
w.startTime = time.Now().UnixNano()
|
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) {
|
func TestWatcher(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestWatcher")
|
assert := internal.NewAssert(t, "TestWatcher")
|
||||||
|
|
||||||
w := &Watcher{}
|
w := NewWatcher()
|
||||||
w.Start()
|
w.Start()
|
||||||
|
|
||||||
longRunningTask()
|
longRunningTask()
|
||||||
|
|||||||
5
go.mod
5
go.mod
@@ -1,3 +1,8 @@
|
|||||||
module github.com/duke-git/lancet/v2
|
module github.com/duke-git/lancet/v2
|
||||||
|
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a
|
||||||
|
golang.org/x/text v0.5.0
|
||||||
|
)
|
||||||
|
|||||||
4
go.sum
Normal file
4
go.sum
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLUYYkDAW9xMFLfxgsvCw=
|
||||||
|
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||||
|
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||||
|
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
@@ -10,7 +10,11 @@
|
|||||||
// Hope that Go can support iterator in future. see https://github.com/golang/go/discussions/54245 and https://github.com/golang/go/discussions/56413
|
// 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
|
package iterator
|
||||||
|
|
||||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
|
)
|
||||||
|
|
||||||
// Iterator supports iterating over a sequence of values of type `E`.
|
// Iterator supports iterating over a sequence of values of type `E`.
|
||||||
type Iterator[T any] interface {
|
type Iterator[T any] interface {
|
||||||
@@ -100,21 +104,15 @@ func (iter *sliceIterator[T]) HasNext() bool {
|
|||||||
|
|
||||||
func (iter *sliceIterator[T]) Next() (T, bool) {
|
func (iter *sliceIterator[T]) Next() (T, bool) {
|
||||||
iter.index++
|
iter.index++
|
||||||
|
|
||||||
ok := iter.index >= 0 && iter.index < len(iter.slice)
|
ok := iter.index >= 0 && iter.index < len(iter.slice)
|
||||||
|
|
||||||
var item T
|
var item T
|
||||||
if ok {
|
if ok {
|
||||||
item = iter.slice[iter.index]
|
item = iter.slice[iter.index]
|
||||||
}
|
}
|
||||||
return item, ok
|
|
||||||
|
|
||||||
// if len(iter.slice) == 0 {
|
return item, ok
|
||||||
// var zero T
|
|
||||||
// return zero, false
|
|
||||||
// }
|
|
||||||
// iter.index++
|
|
||||||
// item := iter.slice[0]
|
|
||||||
// iter.slice = iter.slice[1:]
|
|
||||||
// return item, true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prev implements PrevIterator.
|
// Prev implements PrevIterator.
|
||||||
@@ -142,7 +140,7 @@ func (iter *sliceIterator[T]) Set(value T) {
|
|||||||
|
|
||||||
// FromRange creates a iterator which returns the numeric range between start inclusive and end
|
// 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.
|
// exclusive by the step size. start should be less than end, step shoud be positive.
|
||||||
func FromRange[T lancetconstraints.Number](start, end, step T) Iterator[T] {
|
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) Iterator[T] {
|
||||||
if end < start {
|
if end < start {
|
||||||
panic("RangeIterator: start should be before end")
|
panic("RangeIterator: start should be before end")
|
||||||
} else if step <= 0 {
|
} else if step <= 0 {
|
||||||
@@ -152,15 +150,12 @@ func FromRange[T lancetconstraints.Number](start, end, step T) Iterator[T] {
|
|||||||
return &rangeIterator[T]{start: start, end: end, step: step}
|
return &rangeIterator[T]{start: start, end: end, step: step}
|
||||||
}
|
}
|
||||||
|
|
||||||
type rangeIterator[T lancetconstraints.Number] struct {
|
type rangeIterator[T constraints.Integer | constraints.Float] struct {
|
||||||
start, end, step T
|
start, end, step T
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iter *rangeIterator[T]) HasNext() bool {
|
func (iter *rangeIterator[T]) HasNext() bool {
|
||||||
if iter.start >= iter.end {
|
return iter.start < iter.end
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iter *rangeIterator[T]) Next() (T, bool) {
|
func (iter *rangeIterator[T]) Next() (T, bool) {
|
||||||
@@ -172,3 +167,41 @@ func (iter *rangeIterator[T]) Next() (T, bool) {
|
|||||||
iter.start += iter.step
|
iter.start += iter.step
|
||||||
return num, true
|
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
|
package iterator
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/internal"
|
"github.com/duke-git/lancet/v2/internal"
|
||||||
@@ -47,4 +48,56 @@ func TestSliceIterator(t *testing.T) {
|
|||||||
assert.Equal(false, ok)
|
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 {
|
func (fr *filterIterator[T]) HasNext() bool {
|
||||||
return fr.iter.HasNext()
|
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)
|
||||||
|
}
|
||||||
@@ -11,13 +11,3 @@ type Comparator interface {
|
|||||||
// Descending order: should return 1 -> v1 < v2, 0 -> v1 = v2, -1 -> v1 > v2
|
// Descending order: should return 1 -> v1 < v2, 0 -> v1 = v2, -1 -> v1 > v2
|
||||||
Compare(v1, v2 any) int
|
Compare(v1, v2 any) int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Number contains all types of number and uintptr, used for generics constraint
|
|
||||||
type Number interface {
|
|
||||||
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ordered is a constraint that permits any ordered type: any type that supports the operators < <= >= >
|
|
||||||
type Ordered interface {
|
|
||||||
Number | ~string
|
|
||||||
}
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user