1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-03-01 00:35:28 +08:00

Compare commits

...

100 Commits

Author SHA1 Message Date
dudaodong c260ce493d doc: normalize documents 2023-01-12 15:44:34 +08:00
dudaodong 9ffe96d3ef update readme file 2023-01-12 11:32:43 +08:00
dudaodong d4bba76dc8 fix: fix ExampleSchedule failed 2023-01-09 11:25:14 +08:00
dudaodong adaa3ebc43 Merge branch 'main' into v2 2023-01-09 11:16:13 +08:00
dudaodong 61d38ae3b8 doc: update doc for algorithm package 2023-01-09 11:15:25 +08:00
dudaodong c85d910044 add playground demo 2023-01-09 11:02:41 +08:00
dudaodong d95a7c6101 fix: fix example function bug in function package 2023-01-08 21:09:41 +08:00
dudaodong bce3641ec6 fix: fix example function bug in datetime package 2023-01-08 21:04:39 +08:00
dudaodong ceb134b2fd fix: fix example function bug in datetime package 2023-01-08 21:01:05 +08:00
dudaodong 4b9b1d32c5 release v2.1.13 2023-01-08 20:45:43 +08:00
dudaodong 395e0883c7 fix: fix example test failed of CreateFile 2023-01-08 20:44:23 +08:00
dudaodong a930511054 test&doc: add example and update doc for xerror package 2023-01-08 20:36:32 +08:00
dudaodong 7380721ccc test&doc: add example and update doc for xerror package 2023-01-08 20:36:17 +08:00
dudaodong 936011dc3b fix: fix bug in file test 2023-01-08 20:25:11 +08:00
dudaodong bc0ee08f38 test&doc: add example and update doc for datetime package 2023-01-08 20:16:04 +08:00
dudaodong f1afd753d4 test&doc: add example and update doc for netutil package 2023-01-08 16:57:03 +08:00
dudaodong b05a0a91c3 test&doc: add example and update doc for netutil package 2023-01-08 16:54:29 +08:00
dudaodong da2eb66657 doc: update doc for datastructure package 2023-01-08 15:42:34 +08:00
dudaodong ad20159de2 doc: update doc for datastructure package 2023-01-08 15:41:59 +08:00
dudaodong 278733d3d1 Todo: add todo for playground demo of function 2023-01-07 18:27:07 +08:00
dudaodong 2f184907ff doc: update document for cryptor package 2023-01-07 18:18:23 +08:00
dudaodong 50fcc718ee test: add example for cryptor package 2023-01-07 17:34:42 +08:00
dudaodong cc68feb52d doc&test: add example and update doc for retry package 2023-01-07 14:22:07 +08:00
dudaodong ca2a51b37e test&doc: add example and update doc for function package 2023-01-06 17:12:32 +08:00
dudaodong be444f521d test: add examples for function package 2023-01-06 16:12:44 +08:00
dudaodong e21dd07d46 doc: update doc for validator package 2023-01-06 14:14:00 +08:00
dudaodong 4044deac70 test: add examples for validator package 2023-01-06 11:31:51 +08:00
dudaodong d9c6294775 fix: fix goline error 2023-01-05 14:55:47 +08:00
dudaodong d8505d1a5f doc: update doc for slice package 2023-01-05 14:49:30 +08:00
dudaodong 6498c7d68a test: add examples for slice package 2023-01-05 11:26:56 +08:00
dudaodong 5f0211f0c4 test: add examples for slice package 2023-01-04 14:44:10 +08:00
dudaodong 1de2e2cedd test: add examples for random package 2023-01-03 15:10:42 +08:00
dudaodong c8f8b1b7d9 doc: update doc for fileutil package 2023-01-03 14:33:29 +08:00
dudaodong 3062eb7789 test: add examples for fileutil package 2023-01-03 11:55:23 +08:00
dudaodong 64d5486cc6 doc: add example and update doc for formatter package 2023-01-02 15:35:09 +08:00
dudaodong 6d57891f66 doc: update document for mathutil package 2023-01-02 15:19:47 +08:00
dudaodong 927245e47f test: add example for mathutil package 2023-01-02 14:59:49 +08:00
dudaodong 31fdbee0b5 doc: update document for maputil function 2023-01-02 14:21:23 +08:00
dudaodong 3712819994 test: add exmaple for maputil package 2023-01-02 14:06:12 +08:00
dudaodong 6d7dec1cea doc: update doc for convertor package 2023-01-01 22:00:23 +08:00
dudaodong 9b6a004dbc test: add example for convertor package 2023-01-01 21:24:24 +08:00
dudaodong 3ad6f4bd9e doc: update doc for condition package 2022-12-31 16:47:18 +08:00
dudaodong b8c6746f31 test: add example for condition package 2022-12-31 16:26:43 +08:00
dudaodong 0bf8bbf4cb doc: add example and update docment for channel 2022-12-31 13:38:52 +08:00
dudaodong a6ba1028c5 doc: add example and update docment for channel 2022-12-31 13:35:44 +08:00
dudaodong cc54dd7ec9 doc: add example and update docment for channel 2022-12-31 13:12:16 +08:00
dudaodong 54834dba4c doc: update doc for system package 2022-12-30 14:28:49 +08:00
dudaodong e996d4c945 test: add examples for system package 2022-12-30 14:14:37 +08:00
dudaodong ae92ae7666 test: add examples for system package 2022-12-30 14:14:22 +08:00
dudaodong 526e568d0e doc: add doc for Substring 2022-12-29 20:03:59 +08:00
dudaodong 1dc5e8ac23 feat: add Substring function 2022-12-29 19:55:40 +08:00
dudaodong b5f7b0e670 doc: update document for algorithm package 2022-12-29 15:32:47 +08:00
dudaodong 39c576248c test: add examples for lrucache 2022-12-29 11:43:14 +08:00
dudaodong eb164d1536 test: add examples for lrucache function 2022-12-29 11:43:04 +08:00
dudaodong 68e170080c test: add examples for sort function 2022-12-28 20:18:05 +08:00
dudaodong 652b09135c test: add examples for search function 2022-12-28 17:58:56 +08:00
dudaodong bff24c89bc doc: update strutil document 2022-12-27 17:26:34 +08:00
dudaodong 49a460eef8 doc: update document and add playgound example for strutil package 2022-12-27 16:57:32 +08:00
dudaodong a58e52e53c test: add example function for strutil package 2022-12-27 15:40:51 +08:00
dudaodong b07356423f fix: update format 2022-12-26 17:57:06 +08:00
dudaodong 005dd9d2ab fix: fix word misspelling 2022-12-26 17:51:30 +08:00
dudaodong 65315dafb1 feat: add take iterator 2022-12-26 17:20:14 +08:00
dudaodong b06fb6736d feat: add reduce for iterator 2022-12-26 16:55:24 +08:00
dudaodong b9f0854950 feat: add join iterator 2022-12-26 15:58:44 +08:00
dudaodong 6a2dd328ad feat: add test for map iterator and filter iterator 2022-12-26 15:13:35 +08:00
dudaodong dd1147f6d0 feat: add Channel iterator 2022-12-26 15:02:28 +08:00
dudaodong 6da7ce64af test: add unit test for RangeIterator 2022-12-26 14:24:23 +08:00
dudaodong b7e5d946f1 release v2.1.12 2022-12-15 16:55:20 +08:00
dudaodong 687db4ce79 update readme file 2022-12-15 16:44:30 +08:00
dudaodong a9a4bb8841 update readme file 2022-12-15 16:42:22 +08:00
dudaodong bc6cb5f61b fix code issue in doc 2022-12-15 16:38:50 +08:00
dudaodong 2c57266f8e test: update some test functions 2022-12-15 15:22:01 +08:00
dudaodong 57e49c9520 doc: update document for funcations CamelCase/KebabCase/UpperKebabCase/SnakeCase/UpperSnakeCase 2022-12-14 21:42:43 +08:00
dudaodong 985c9a5d9a refactor: refact CamelCase function 2022-12-14 21:27:29 +08:00
dudaodong 5cfb11f036 feat: fix and add SnakeCase/UpperSnakeCase 2022-12-14 21:17:30 +08:00
dudaodong 5b3d48a1e7 feat: fix and add KebabCase/UpperKebabCase 2022-12-14 21:09:22 +08:00
dudaodong d0576e028f clean code 2022-12-13 19:52:37 +08:00
dudaodong 76bdec2b54 test: add cases for Capitalize 2022-12-13 16:16:16 +08:00
dudaodong fa20aba3a7 fix: fix CamelCase function bug 2022-12-13 14:23:32 +08:00
dudaodong 7a4a429e23 test: add cases for Capitalize 2022-12-12 21:11:19 +08:00
dudaodong a70ec6ad1e refactor: use constraints from golang.org/x/exp/constraints 2022-12-11 11:25:34 +08:00
dudaodong e435fa271b doc: update doc for Comma 2022-12-10 21:03:16 +08:00
dudaodong 1533d00891 refactor: update Comma function 2022-12-10 20:59:27 +08:00
dudaodong 8b99641de0 test: remove print info in test function 2022-12-10 19:19:49 +08:00
dudaodong 251f899f18 fix: TestExecCommand failed in linux/macos 2022-12-10 19:12:19 +08:00
dudaodong 00407e5182 fix: fix lint issue 2022-12-10 19:09:18 +08:00
dudaodong 4e457ad672 change: change update and insert function in link datastruture 2022-12-10 17:45:29 +08:00
dudaodong 7d8d9c3543 fix: fix lint issue 2022-12-10 16:55:06 +08:00
dudaodong 1197e8d1b6 fix: fix lint issue 2022-12-10 16:53:41 +08:00
dudaodong 13bbe19ab2 fix: fix lint issue 2022-12-10 16:41:40 +08:00
dudaodong 2725575d2f doc: add doc for IsGBK' 2022-12-09 19:28:45 +08:00
dudaodong 037d2729ce doc: update doc for ExecCommand 2022-12-09 19:20:15 +08:00
dudaodong 09d98745b0 fix: fix ExecCommand bug in windows 2022-12-09 19:10:55 +08:00
dudaodong af5cfe6da1 feat: add IsGBK validator 2022-12-09 17:36:59 +08:00
Mickls d59259bbe0 feat: A more reasonable IndexOf function (#66) 2022-12-09 11:31:40 +08:00
dudaodong 3189628d54 fix: fix AesCfbDecrypt 2022-12-08 15:07:40 +08:00
dudaodong 62c5e251a5 remove website 2022-12-08 14:55:21 +08:00
dudaodong 6e6444c8c0 refator: clean code 2022-12-06 20:20:36 +08:00
dudaodong dd613e98b2 refator: clean code 2022-12-06 20:00:41 +08:00
dudaodong 2d905ab03e fix: fix word misspelling 2022-12-04 11:25:02 +08:00
134 changed files with 11648 additions and 4322 deletions
+913 -309
View File
File diff suppressed because it is too large Load Diff
+932 -314
View File
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
View 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)
} }
+12 -9
View File
@@ -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: https://go.dev/play/p/IsS7rgn5s3x
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int {
for i, v := range slice { 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
View 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
}
+11 -5
View File
@@ -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))
} }
+16 -9
View File
@@ -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
View 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]
}
+1
View File
@@ -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)
+47 -43
View File
@@ -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: https://go.dev/play/p/7aB4KyMMp9A
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: https://go.dev/play/p/k5N_ALVmYjE
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: https://go.dev/play/p/4J1zAWttP85
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: https://go.dev/play/p/9Utt-1pDr2J
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: https://go.dev/play/p/2VYFMexEvTm
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: https://go.dev/play/p/3TQPKnCirrP
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: https://go.dev/play/p/qmWSy1NVF-Y
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: https://go.dev/play/p/Wqz9rwioPww
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: https://go.dev/play/p/lm_GoS6aDjo
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
View 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
}
+17 -35
View File
@@ -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
+14 -6
View File
@@ -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
View 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
}
+54 -35
View File
@@ -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,53 +95,58 @@ 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 convertion // todo: maybe we should't supprt other type conversion
// v := reflect.ValueOf(value) // v := reflect.ValueOf(value)
// log.Panicf("Unsupported data type: %s ", v.String()) // log.Panicf("Unsupported data type: %s ", v.String())
// return "" // return ""
} }
} }
// 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
View 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
}
+5 -9
View File
@@ -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
View File
@@ -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
}
-62
View File
@@ -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))
}
+21 -11
View File
@@ -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
View 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
View File
@@ -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
}
-62
View File
@@ -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
View 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
View 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
View File
@@ -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
}
-20
View File
@@ -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))
}
+4 -4
View File
@@ -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()
-2
View File
@@ -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) {
+73 -76
View File
@@ -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
} }
+5 -18
View File
@@ -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)
+72 -77
View File
@@ -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)
+8 -31
View File
@@ -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())
} }
+32 -32
View File
@@ -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) {
-7
View File
@@ -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())
} }
+59 -62
View File
@@ -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())
} }
-2
View File
@@ -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())
} }
+21 -15
View File
@@ -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())
} }
-2
View File
@@ -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()
+1 -11
View File
@@ -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))
} }
+24 -24
View File
@@ -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
+16 -8
View File
@@ -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)
} }
-3
View File
@@ -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)
+44 -22
View File
@@ -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
View 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
// }
+2 -3
View File
@@ -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)
} }
} }
+155 -138
View File
@@ -40,8 +40,6 @@ import (
## Documentation ## Documentation
### <span id="BubbleSort">BubbleSort</span> ### <span id="BubbleSort">BubbleSort</span>
<p>Sort slice with bubble sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with bubble sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
@@ -60,10 +58,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -74,19 +71,21 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.BubbleSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.BubbleSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="InsertionSort">InsertionSort</span> ### <span id="InsertionSort">InsertionSort</span>
<p>Sort slice with insertion sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with insertion sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
@@ -105,17 +104,16 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type people struct {
type people struct {
Name string Name string
Age int Age int
} }
// PeopleAageComparator sort people slice by age field // PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{} type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator // Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int { func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people) p1, _ := v1.(people)
p2, _ := v2.(people) p2, _ := v2.(people)
@@ -125,33 +123,31 @@ func main() {
} else if p1.Age > p2.Age { } else if p1.Age > p2.Age {
return 1 return 1
} }
return 0 return 0
}
//decending order func main() {
// if p1.Age > p2.Age { peoples := []people{
// return -1
// } else if p1.Age < p2.Age {
// return 1
// }
}
var peoples = []people{
{Name: "a", Age: 20}, {Name: "a", Age: 20},
{Name: "b", Age: 10}, {Name: "b", Age: 10},
{Name: "c", Age: 17}, {Name: "c", Age: 17},
{Name: "d", Age: 8}, {Name: "d", Age: 8},
{Name: "e", Age: 28}, {Name: "e", Age: 28},
} }
comparator := &peopleAgeComparator{} comparator := &peopleAgeComparator{}
algorithm.InsertionSort(peoples, comparator) algorithm.InsertionSort(peoples, comparator)
fmt.Println(peoples) //[{d 8} {b 10} {c 17} {a 20} {e 28}] fmt.Println(peoples)
// Output:
//[{d 8} {b 10} {c 17} {a 20} {e 28}]
} }
``` ```
### <span id="SelectionSort">SelectionSort</span> ### <span id="SelectionSort">SelectionSort</span>
<p>Sort slice with selection sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with selection sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
@@ -170,10 +166,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -184,19 +179,21 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.SelectionSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.SelectionSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="ShellSort">ShellSort</span> ### <span id="ShellSort">ShellSort</span>
<p>Sort slice with shell sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with shell sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
@@ -215,10 +212,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -229,19 +225,21 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.ShellSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.ShellSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="QuickSort">QuickSort</span> ### <span id="QuickSort">QuickSort</span>
<p>Sort slice with quick sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with quick sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
@@ -260,10 +258,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -274,19 +271,21 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.QuickSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.QuickSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="HeapSort">HeapSort</span> ### <span id="HeapSort">HeapSort</span>
<p>Sort slice with heap sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with heap sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
@@ -305,10 +304,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -319,19 +317,21 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.HeapSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.HeapSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="MergeSort">MergeSort</span> ### <span id="MergeSort">MergeSort</span>
<p>Sort slice with merge sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with merge sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
@@ -350,10 +350,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -364,18 +363,21 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.MergeSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.MergeSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="CountSort">CountSort</span> ### <span id="CountSort">CountSort</span>
<p>Sort slice with count sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p> <p>Sort slice with count sort algorithm. Param comparator should implements lancetconstraints.Comparator.</p>
@@ -394,10 +396,10 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -408,19 +410,21 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
sortedSlice := algorithm.CountSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]int{1, 2, 3, 4, 5, 6} sortedNums := algorithm.CountSort(numbers, comparator)
fmt.Println(sortedNums)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="BinarySearch">BinarySearch</span> ### <span id="BinarySearch">BinarySearch</span>
<p>BinarySearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p> <p>BinarySearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p>
@@ -439,10 +443,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -453,20 +456,24 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8} func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{} comparator := &intComparator{}
foundIndex := algorithm.BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator) result1 := algorithm.BinarySearch(numbers, 5, 0, len(numbers)-1, comparator)
fmt.Println(notFoundIndex) //-1 result2 := algorithm.BinarySearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
} }
``` ```
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span> ### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
<p>BinaryIterativeSearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p> <p>BinaryIterativeSearch search for target within a sorted slice, recursive call itself. If a target is found, the index of the target is returned. Else the function return -1.</p>
@@ -485,10 +492,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -499,28 +505,31 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8} func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{} comparator := &intComparator{}
foundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator) result1 := algorithm.BinaryIterativeSearch(numbers, 5, 0, len(numbers)-1, comparator)
fmt.Println(notFoundIndex) //-1 result2 := algorithm.BinaryIterativeSearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
} }
``` ```
### <span id="LinearSearch">LinearSearch</span> ### <span id="LinearSearch">LinearSearch</span>
<p>LinearSearch Simple linear search algorithm that iterates over all elements of an slice. If a target is found, the index of the target is returned. Else the function return -1.</p> <p>return the index of target in slice base on equal function.If a target is found, the index of the target is returned. Else the function return -1.</p>
<b>Signature:</b> <b>Signature:</b>
```go ```go
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int
``` ```
<b>Example:</b> <b>Example:</b>
@@ -533,34 +542,24 @@ import (
) )
func main() { func main() {
type intComparator struct{} numbers := []int{3, 4, 5, 3, 2, 1}
func (c *intComparator) Compare(v1 any, v2 any) int { equalFunc := func(a, b int) bool {
val1, _ := v1.(int) return a == b
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} result1 := algorithm.LinearSearch(numbers, 3, equalFunc)
comparator := &intComparator{} result2 := algorithm.LinearSearch(numbers, 6, equalFunc)
foundIndex := algorithm.LinearSearch(intSlice, 5, comparator)
fmt.Println(foundIndex) //2
notFoundIndex := algorithm.LinearSearch(sortedNumbers, 0, comparator) fmt.Println(result1)
fmt.Println(notFoundIndex) //-1 fmt.Println(result2)
// Output:
// 0
// -1
} }
``` ```
### <span id="LRUCache">LRUCache</span> ### <span id="LRUCache">LRUCache</span>
<p>LRUCache implements mem cache with lru.</p> <p>LRUCache implements mem cache with lru.</p>
@@ -570,6 +569,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>
@@ -587,9 +588,25 @@ func main() {
cache.Put(1, 1) cache.Put(1, 1)
cache.Put(2, 2) cache.Put(2, 2)
_, ok := cache.Get(0) // ok -> false result1, ok1 := cache.Get(1)
result2, ok2 := cache.Get(2)
result3, ok3 := cache.Get(3)
v, ok := cache.Get(1) // v->1, ok->true fmt.Println(result1, ok1)
fmt.Println(result2, ok2)
fmt.Println(result3, ok3)
fmt.Println(cache.Len())
ok := cache.Delete(2)
fmt.Println(ok)
// Output:
// 1 true
// 2 true
// 0 false
// 2
// true
} }
``` ```
+180 -163
View File
@@ -40,17 +40,15 @@ import (
## 文档 ## 文档
### <span id="BubbleSort">BubbleSort</span> ### <span id="BubbleSort">BubbleSort</span>
<p>冒泡排序,参数comparator需要实现包lancetconstraints.Comparator</p> <p>冒泡排序,参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b> <b>示例:</b>
```go ```go
package main package main
@@ -60,10 +58,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -74,28 +71,30 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.BubbleSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.BubbleSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="InsertionSort">InsertionSort</span> ### <span id="InsertionSort">InsertionSort</span>
<p>插入排序,参数comparator需要实现包lancetconstraints.Comparator</p> <p>插入排序,参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b> <b>示例:</b>
```go ```go
package main package main
@@ -105,17 +104,16 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type people struct {
type people struct {
Name string Name string
Age int Age int
} }
// PeopleAageComparator sort people slice by age field // PeopleAageComparator sort people slice by age field
type peopleAgeComparator struct{} type peopleAgeComparator struct{}
// Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator // Compare implements github.com/duke-git/lancet/lancetconstraints/constraints.go/Comparator
func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int { func (pc *peopleAgeComparator) Compare(v1 any, v2 any) int {
p1, _ := v1.(people) p1, _ := v1.(people)
p2, _ := v2.(people) p2, _ := v2.(people)
@@ -125,42 +123,40 @@ func main() {
} else if p1.Age > p2.Age { } else if p1.Age > p2.Age {
return 1 return 1
} }
return 0 return 0
}
//decending order func main() {
// if p1.Age > p2.Age { peoples := []people{
// return -1
// } else if p1.Age < p2.Age {
// return 1
// }
}
var peoples = []people{
{Name: "a", Age: 20}, {Name: "a", Age: 20},
{Name: "b", Age: 10}, {Name: "b", Age: 10},
{Name: "c", Age: 17}, {Name: "c", Age: 17},
{Name: "d", Age: 8}, {Name: "d", Age: 8},
{Name: "e", Age: 28}, {Name: "e", Age: 28},
} }
comparator := &peopleAgeComparator{} comparator := &peopleAgeComparator{}
algorithm.InsertionSort(peoples, comparator) algorithm.InsertionSort(peoples, comparator)
fmt.Println(intSlice) //[{d 8} {b 10} {c 17} {a 20} {e 28}] fmt.Println(peoples)
// Output:
//[{d 8} {b 10} {c 17} {a 20} {e 28}]
} }
``` ```
### <span id="SelectionSort">SelectionSort</span> ### <span id="SelectionSort">SelectionSort</span>
<p>选择排序,参数comparator需要实现包lancetconstraints.Comparator</p> <p>选择排序,参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b> <b>示例:</b>
```go ```go
package main package main
@@ -170,10 +166,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -184,28 +179,30 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.SelectionSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.SelectionSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="ShellSort">ShellSort</span> ### <span id="ShellSort">ShellSort</span>
<p>希尔排序,参数comparator需要实现包lancetconstraints.Comparator</p> <p>希尔排序,参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b> <b>示例:</b>
```go ```go
package main package main
@@ -215,10 +212,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -229,28 +225,30 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.ShellSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.ShellSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="QuickSort">QuickSort</span> ### <span id="QuickSort">QuickSort</span>
<p>快速排序,参数comparator需要实现包lancetconstraints.Comparator</p> <p>快速排序,参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) []T func QuickSort[T any](slice []T comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b> <b>示例:</b>
```go ```go
package main package main
@@ -260,10 +258,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -274,28 +271,30 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.QuickSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.QuickSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="HeapSort">HeapSort</span> ### <span id="HeapSort">HeapSort</span>
<p>堆排序,参数comparator需要实现包lancetconstraints.Comparator</p> <p>堆排序,参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) []T func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b> <b>示例:</b>
```go ```go
package main package main
@@ -305,10 +304,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -319,28 +317,30 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.HeapSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.HeapSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="MergeSort">MergeSort</span> ### <span id="MergeSort">MergeSort</span>
<p>归并排序,参数comparator需要实现包lancetconstraints.Comparator</p> <p>归并排序,参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator) func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator)
``` ```
<b>Example:</b> <b>示例:</b>
```go ```go
package main package main
@@ -350,10 +350,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -364,27 +363,30 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
algorithm.MergeSort(intSlice, comparator)
fmt.Println(intSlice) //[]int{1, 2, 3, 4, 5, 6} algorithm.MergeSort(numbers, comparator)
fmt.Println(numbers)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="CountSort">CountSort</span> ### <span id="CountSort">CountSort</span>
<p>计数排序,参数comparator需要实现包lancetconstraints.Comparator</p> <p>计数排序,参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T
``` ```
<b>Example:</b> <b>示例:</b>
```go ```go
package main package main
@@ -394,10 +396,10 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() {
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -408,28 +410,30 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} func main() {
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{} comparator := &intComparator{}
sortedSlice := algorithm.CountSort(intSlice, comparator)
fmt.Println(sortedSlice) //[]int{1, 2, 3, 4, 5, 6} sortedNums := algorithm.CountSort(numbers, comparator)
fmt.Println(sortedNums)
// Output:
// [1 2 3 4 5 6]
} }
``` ```
### <span id="BinarySearch">BinarySearch</span> ### <span id="BinarySearch">BinarySearch</span>
<p>二分递归查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator</p> <p>二分递归查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
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
``` ```
<b>Example:</b> <b>示例:</b>
```go ```go
package main package main
@@ -439,10 +443,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -453,29 +456,33 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8} func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{} comparator := &intComparator{}
foundIndex := algorithm.BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator) result1 := algorithm.BinarySearch(numbers, 5, 0, len(numbers)-1, comparator)
fmt.Println(notFoundIndex) //-1 result2 := algorithm.BinarySearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
} }
``` ```
### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span> ### <span id="BinaryIterativeSearch">BinaryIterativeSearch</span>
<p>二分迭代查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator</p> <p>二分迭代查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
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
``` ```
<b>Example:</b> <b>示例:</b>
```go ```go
package main package main
@@ -485,10 +492,9 @@ import (
"github.com/duke-git/lancet/v2/algorithm" "github.com/duke-git/lancet/v2/algorithm"
) )
func main() { type intComparator struct{}
type intComparator struct{}
func (c *intComparator) Compare(v1 any, v2 any) int { func (c *intComparator) Compare(v1 any, v2 any) int {
val1, _ := v1.(int) val1, _ := v1.(int)
val2, _ := v2.(int) val2, _ := v2.(int)
@@ -499,30 +505,33 @@ func main() {
return 1 return 1
} }
return 0 return 0
} }
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8} func main() {
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{} comparator := &intComparator{}
foundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator)
fmt.Println(foundIndex) //4
notFoundIndex := algorithm.BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator) result1 := algorithm.BinaryIterativeSearch(numbers, 5, 0, len(numbers)-1, comparator)
fmt.Println(notFoundIndex) //-1 result2 := algorithm.BinaryIterativeSearch(numbers, 9, 0, len(numbers)-1, comparator)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 4
// -1
} }
``` ```
### <span id="LinearSearch">LinearSearch</span> ### <span id="LinearSearch">LinearSearch</span>
<p>线性查找,返回元素索引,未找到元素返回-1,参数comparator需要实现包lancetconstraints.Comparator</p> <p>基于传入的相等函数线性查找元素,返回元素索引,未找到元素返回-1</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int
``` ```
<b>Example:</b> <b>示例:</b>
```go ```go
package main package main
@@ -533,36 +542,26 @@ import (
) )
func main() { func main() {
type intComparator struct{} numbers := []int{3, 4, 5, 3, 2, 1}
func (c *intComparator) Compare(v1 any, v2 any) int { equalFunc := func(a, b int) bool {
val1, _ := v1.(int) return a == b
val2, _ := v2.(int)
//ascending order
if val1 < val2 {
return -1
} else if val1 > val2 {
return 1
}
return 0
} }
intSlice := []int{2, 1, 5, 3, 6, 4} result1 := algorithm.LinearSearch(numbers, 3, equalFunc)
comparator := &intComparator{} result2 := algorithm.LinearSearch(numbers, 6, equalFunc)
foundIndex := algorithm.LinearSearch(intSlice, 5, comparator)
fmt.Println(foundIndex) //2
notFoundIndex := algorithm.LinearSearch(sortedNumbers, 0, comparator) fmt.Println(result1)
fmt.Println(notFoundIndex) //-1 fmt.Println(result2)
// Output:
// 0
// -1
} }
``` ```
### <span id="LRUCache">LRUCache</span> ### <span id="LRUCache">LRUCache</span>
<p>lru实现缓存</p> <p>lru算法实现缓存</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -570,8 +569,10 @@ 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>示例:</b>
```go ```go
package main package main
@@ -587,9 +588,25 @@ func main() {
cache.Put(1, 1) cache.Put(1, 1)
cache.Put(2, 2) cache.Put(2, 2)
_, ok := cache.Get(0) // ok -> false result1, ok1 := cache.Get(1)
result2, ok2 := cache.Get(2)
result3, ok3 := cache.Get(3)
v, ok := cache.Get(1) // v->1, ok->true fmt.Println(result1, ok1)
fmt.Println(result2, ok2)
fmt.Println(result3, ok3)
fmt.Println(cache.Len())
ok := cache.Delete(2)
fmt.Println(ok)
// Output:
// 1 true
// 2 true
// 0 false
// 2
// true
} }
``` ```
+129 -78
View File
@@ -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,12 +57,10 @@ import (
) )
func main() { func main() {
c := concurrency.NewChannel() c := concurrency.NewChannel[int]()
} }
``` ```
### <span id="Bridge">Bridge</span> ### <span id="Bridge">Bridge</span>
<p>Link multiple channels into one channel until cancel the context.</p> <p>Link multiple channels into one channel until cancel the context.</p>
@@ -70,7 +68,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,39 +85,42 @@ 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
} }
``` ```
### <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,30 +137,29 @@ 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="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 +176,67 @@ 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>
<p>Creates a channel, then put values into the channel.</p>
<b>Signature:</b>
```go
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
intStream := c.Generate(ctx, 1, 2, 3)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
// Output:
// 1
// 2
// 3
}
```
### <span id="RepeatFn">RepeatFn</span> ### <span id="RepeatFn">RepeatFn</span>
<p>Return a chan, excutes fn repeatly, and put the result into retruned chan until cancel context.</p> <p>Create a channel, excutes fn repeatly, and put the result into the channel, until close context.</p>
<b>Signature:</b> <b>Signature:</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>Example:</b> <b>Example:</b>
@@ -212,21 +253,24 @@ 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
} }
``` ```
### <span id="Or">Or</span> ### <span id="Or">Or</span>
<p>Read one or more channels into one channel, will close when any readin channel is closed.</p> <p>Read one or more channels into one channel, will close when any readin channel is closed.</p>
@@ -234,7 +278,7 @@ func main() {
<b>Signature:</b> <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 +293,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,22 +303,17 @@ 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
} }
``` ```
### <span id="OrDone">OrDone</span> ### <span id="OrDone">OrDone</span>
<p>Read a channel into another channel, will close until cancel context.</p> <p>Read a channel into another channel, will close until cancel context.</p>
@@ -282,7 +321,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,26 +338,28 @@ 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
} }
``` ```
### <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 +376,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,25 +384,28 @@ 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
} }
``` ```
### <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 +422,20 @@ 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
} }
``` ```
+132 -83
View File
@@ -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,20 +57,18 @@ import (
) )
func main() { func main() {
c := concurrency.NewChannel() c := concurrency.NewChannel[int]()
} }
``` ```
### <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>
@@ -87,39 +85,42 @@ 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
} }
``` ```
### <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>
@@ -136,30 +137,67 @@ 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="Generate">Generate</span>
<p>根据传入的值,生成channel.</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
intStream := c.Generate(ctx, 1, 2, 3)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
// Output:
// 1
// 2
// 3
}
```
### <span id="Repeat">Repeat</span> ### <span id="Repeat">Repeat</span>
<p>返回一个chan,将参数`values`重复放入chan,直到取消上下文。</p> <p>返回一个channel,将参数`values`重复放入channel,直到取消上下文。</p>
<b>函数签名:</b> <b>函数签名:</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>例子:</b> <b>例子:</b>
@@ -176,26 +214,29 @@ 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="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>
@@ -212,29 +253,31 @@ 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
} }
``` ```
### <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 +292,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,30 +302,25 @@ 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
} }
``` ```
### <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,26 +337,28 @@ 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
} }
``` ```
### <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 +375,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,25 +383,28 @@ 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
} }
``` ```
### <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 +421,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
} }
``` ```
+75 -29
View File
@@ -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)
@@ -57,40 +58,51 @@ import (
func main() { func main() {
// bool // bool
fmt.Println(condition.Bool(false)) // false result1 := condition.Bool(false)
fmt.Println(condition.Bool(true)) // true result2 := condition.Bool(true)
fmt.Println(result1) // false
fmt.Println(result2) // true
// integer // integer
fmt.Println(condition.Bool(0)) // false result3 := condition.Bool(0)
fmt.Println(condition.Bool(1)) // true result4 := condition.Bool(1)
fmt.Println(result3) // false
// float fmt.Println(result4) // true
fmt.Println(condition.Bool(0.0)) // false
fmt.Println(condition.Bool(0.1)) // true
// string // string
fmt.Println(condition.Bool("")) // false result5 := condition.Bool("")
fmt.Println(condition.Bool(" ")) // true result6 := condition.Bool(" ")
fmt.Println(condition.Bool("0")) // true fmt.Println(result5) // false
fmt.Println(result6) // true
// slice // slice
var nums [2]int nums := []int{}
fmt.Println(condition.Bool(nums)) // false result7 := condition.Bool(nums)
nums = [2]int{0, 1}
fmt.Println(condition.Bool(nums)) // true
// map nums = append(nums, 1, 2)
fmt.Println(condition.Bool(map[string]string{})) // false result8 := condition.Bool(nums)
fmt.Println(condition.Bool(map[string]string{"a": "a"})) // true fmt.Println(result7) // false
fmt.Println(result8) // true
// struct // struct
fmt.Println(condition.Bool(struct{}{})) // false result9 = condition.Bool(struct{}{})
fmt.Println(condition.Bool(time.Now())) // true fmt.Println(result8) // false
// Output:
// false
// true
// false
// true
// false
// true
// false
// true
// false
} }
``` ```
### <span id="And">And</span> ### <span id="And">And</span>
<p>Returns true if both a and b are truthy.</p> <p>Returns true if both a and b are truthy.</p>
@@ -120,7 +132,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 +160,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 +188,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 +209,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>
@@ -250,10 +288,18 @@ import (
) )
func main() { func main() {
trueValue := "1" conditionTrue := 2 > 1
falseValue := "0" result1 := condition.TernaryOperator(conditionTrue, 0, 1)
fmt.Println(condition.TernaryOperator(true, trueValue, falseValue)) // "1" conditionFalse := 2 > 3
result2 := condition.TernaryOperator(conditionFalse, 0, 1)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 0
// 1
} }
``` ```
+69 -34
View File
@@ -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)
@@ -56,40 +57,50 @@ import (
func main() { func main() {
// bool // bool
fmt.Println(condition.Bool(false)) // false result1 := condition.Bool(false)
fmt.Println(condition.Bool(true)) // true result2 := condition.Bool(true)
fmt.Println(result1) // false
fmt.Println(result2) // true
// integer // integer
fmt.Println(condition.Bool(0)) // false result3 := condition.Bool(0)
fmt.Println(condition.Bool(1)) // true result4 := condition.Bool(1)
fmt.Println(result3) // false
// float fmt.Println(result4) // true
fmt.Println(condition.Bool(0.0)) // false
fmt.Println(condition.Bool(0.1)) // true
// string // string
fmt.Println(condition.Bool("")) // false result5 := condition.Bool("")
fmt.Println(condition.Bool(" ")) // true result6 := condition.Bool(" ")
fmt.Println(condition.Bool("0")) // true fmt.Println(result5) // false
fmt.Println(result6) // true
// slice // slice
var nums [2]int nums := []int{}
fmt.Println(condition.Bool(nums)) // false result7 := condition.Bool(nums)
nums = [2]int{0, 1}
fmt.Println(condition.Bool(nums)) // true
// map nums = append(nums, 1, 2)
fmt.Println(condition.Bool(map[string]string{})) // false result8 := condition.Bool(nums)
fmt.Println(condition.Bool(map[string]string{"a": "a"})) // true fmt.Println(result7) // false
fmt.Println(result8) // true
// struct // struct
fmt.Println(condition.Bool(struct{}{})) // false result9 = condition.Bool(struct{}{})
fmt.Println(condition.Bool(time.Now())) // true fmt.Println(result8) // false
// Output:
// false
// true
// false
// true
// false
// true
// false
// true
// false
} }
``` ```
### <span id="And">And</span> ### <span id="And">And</span>
<p>逻辑且操作,当切仅当a和b都为true时返回true</p> <p>逻辑且操作,当切仅当a和b都为true时返回true</p>
@@ -116,8 +127,6 @@ func main() {
} }
``` ```
### <span id="Or">Or</span> ### <span id="Or">Or</span>
<p>逻辑或操作,当切仅当a和b都为false时返回false</p> <p>逻辑或操作,当切仅当a和b都为false时返回false</p>
@@ -144,8 +153,6 @@ func main() {
} }
``` ```
### <span id="Xor">Xor</span> ### <span id="Xor">Xor</span>
<p>逻辑异或操作,a和b相同返回falsea和b不相同返回true</p> <p>逻辑异或操作,a和b相同返回falsea和b不相同返回true</p>
@@ -172,8 +179,6 @@ func main() {
} }
``` ```
### <span id="Nor">Nor</span> ### <span id="Nor">Nor</span>
<p>异或的取反操作</p> <p>异或的取反操作</p>
@@ -196,11 +201,35 @@ 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>
@@ -228,8 +257,6 @@ func main() {
} }
``` ```
### <span id="TernaryOperator">TernaryOperator</span> ### <span id="TernaryOperator">TernaryOperator</span>
<p>三元运算符</p> <p>三元运算符</p>
@@ -249,10 +276,18 @@ import (
) )
func main() { func main() {
trueValue := "1" conditionTrue := 2 > 1
falseValue := "0" result1 := condition.TernaryOperator(conditionTrue, 0, 1)
fmt.Println(condition.TernaryOperator(true, trueValue, falseValue)) // "1" conditionFalse := 2 > 3
result2 := condition.TernaryOperator(conditionFalse, 0, 1)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 0
// 1
} }
``` ```
+156 -87
View File
@@ -40,8 +40,6 @@ import (
## Documentation ## Documentation
### <span id="ColorHexToRGB">ColorHexToRGB</span> ### <span id="ColorHexToRGB">ColorHexToRGB</span>
<p>Convert color hex to color rgb.</p> <p>Convert color hex to color rgb.</p>
@@ -63,12 +61,14 @@ import (
func main() { func main() {
colorHex := "#003366" colorHex := "#003366"
r, g, b := convertor.ColorHexToRGB(colorHex) r, g, b := convertor.ColorHexToRGB(colorHex)
fmt.Println(r, g, b) //0,51,102
fmt.Println(r, g, b)
// Output:
// 0 51 102
} }
``` ```
### <span id="ColorRGBToHex">ColorRGBToHex</span> ### <span id="ColorRGBToHex">ColorRGBToHex</span>
<p>Convert color rgb to color hex.</p> <p>Convert color rgb to color hex.</p>
@@ -92,17 +92,18 @@ func main() {
r := 0 r := 0
g := 51 g := 51
b := 102 b := 102
colorHex := convertor.ColorRGBToHex(r, g, b) colorHex := ColorRGBToHex(r, g, b)
fmt.Println(colorHex) //#003366 fmt.Println(colorHex)
// Output:
// #003366
} }
``` ```
### <span id="ToBool">ToBool</span> ### <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>
@@ -120,25 +121,29 @@ import (
) )
func main() { func main() {
v1, _ := convertor.ToBool("1") cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
fmt.Println(v1) //true
v2, _ := convertor.ToBool("true") for i := 0; i < len(cases); i++ {
fmt.Println(v2) //true result, _ := convertor.ToBool(cases[i])
fmt.Println(result)
}
v3, _ := convertor.ToBool("True") // Output:
fmt.Println(v3) //true // true
// true
v4, _ := convertor.ToBool("123") // true
fmt.Println(v4) //false // false
// false
// false
// false
// false
// false
} }
``` ```
### <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>
@@ -156,16 +161,18 @@ import (
) )
func main() { func main() {
bytesData, err := convertor.ToBytes("0") bytesData, err := convertor.ToBytes("abc")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
fmt.Println(bytesData) //[]bytes{3, 4, 0, 0}
fmt.Println(bytesData)
// Output:
// [97 98 99]
} }
``` ```
### <span id="ToChar">ToChar</span> ### <span id="ToChar">ToChar</span>
<p>Convert string to char slice.</p> <p>Convert string to char slice.</p>
@@ -186,21 +193,24 @@ import (
) )
func main() { func main() {
chars := convertor.ToChar("") result1 := convertor.ToChar("")
fmt.Println(chars) //[]string{""} result2 := convertor.ToChar("abc")
result3 := convertor.ToChar("1 2#3")
chars = convertor.ToChar("abc") fmt.Println(result1)
fmt.Println(chars) //[]string{"a", "b", "c"} fmt.Println(result2)
fmt.Println(result3)
chars = convertor.ToChar("1 2#3") // Output:
fmt.Println(chars) //[]string{"1", " ", "2", "#", "3"} // []
// [a b c]
// [1 2 # 3]
} }
``` ```
### <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>
@@ -219,26 +229,24 @@ import (
func main() { func main() {
ch := convertor.ToChannel([]int{1, 2, 3}) ch := convertor.ToChannel([]int{1, 2, 3})
result1 := <-ch
result2 := <-ch
result3 := <-ch
val1, _ := <-ch fmt.Println(result1)
fmt.Println(val1) //1 fmt.Println(result2)
fmt.Println(result3)
val2, _ := <-ch // Output:
fmt.Println(val2) //2 // 1
// 2
val3, _ := <-ch // 3
fmt.Println(val3) //3
_, ok := <-ch
fmt.Println(ok) //false
} }
``` ```
### <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>
@@ -256,22 +264,33 @@ import (
) )
func main() { func main() {
v, err := convertor.ToFloat("") result1, _ := convertor.ToFloat("")
if err != nil { result2, err := convertor.ToFloat("abc")
fmt.Println(err) //strconv.ParseFloat: parsing "": invalid syntax result3, _ := convertor.ToFloat("-1")
} result4, _ := convertor.ToFloat("-.11")
fmt.Println(v) //0 result5, _ := convertor.ToFloat("1.23e3")
result6, _ := convertor.ToFloat(true)
v, _ = convertor.ToFloat("-.11") fmt.Println(result1)
fmt.Println(v) //-0.11 fmt.Println(result2, err)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// 0
// 0 strconv.ParseFloat: parsing "": invalid syntax
// -1
// -0.11
// 1230
// 0
} }
``` ```
### <span id="ToInt">ToInt</span> ### <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>
@@ -289,19 +308,27 @@ import (
) )
func main() { func main() {
v, err := convertor.ToInt("") result1, _ := convertor.ToInt("123")
if err != nil { result2, _ := convertor.ToInt("-123")
fmt.Println(err) //strconv.ParseInt: parsing "": invalid syntax result3, _ := convertor.ToInt(float64(12.3))
} result4, err := convertor.ToInt("abc")
fmt.Println(v) //0 result5, _ := convertor.ToInt(true)
v, _ = convertor.ToFloat(1.12) fmt.Println(result1)
fmt.Println(v) //1 fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4, err)
fmt.Println(result5)
// Output:
// 123
// -123
// 12
// 0 strconv.ParseInt: parsing "": invalid syntax
// 0
} }
``` ```
### <span id="ToJson">ToJson</span> ### <span id="ToJson">ToJson</span>
<p>Convert interface to json string. If param can't be converted, will return "" and error. </p> <p>Convert interface to json string. If param can't be converted, will return "" and error. </p>
@@ -322,17 +349,23 @@ import (
) )
func main() { func main() {
var aMap = map[string]int{"a": 1, "b": 2, "c": 3} aMap := map[string]int{"a": 1, "b": 2, "c": 3}
jsonStr, _ := convertor.ToJson(aMap) result, err := ToJson(aMap)
fmt.Printf("%q", jsonStr) //"{\"a\":1,\"b\":2,\"c\":3}"
if err != nil {
fmt.Printf("%v", err)
}
fmt.Println(result)
// Output:
// {"a":1,"b":2,"c":3}
} }
``` ```
### <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>
@@ -358,16 +391,18 @@ func main() {
{name: "Hello", code: 100}, {name: "Hello", code: 100},
{name: "Hi", code: 101}, {name: "Hi", code: 101},
} }
result := convertor.ToMap(messages, func(msg Message) (int, string) { result := convertor.ToMap(messages, func(msg Message) (int, string) {
return msg.code, msg.name return msg.code, msg.name
}) })
fmt.Println(result) //{100: "Hello", 101: "Hi"} fmt.Println(result)
// Output:
// map[100:Hello 101:Hi]
} }
``` ```
### <span id="ToPointer">ToPointer</span> ### <span id="ToPointer">ToPointer</span>
<p>Returns a pointer to passed value. </p> <p>Returns a pointer to passed value. </p>
@@ -389,11 +424,13 @@ import (
func main() { func main() {
result := convertor.ToPointer(123) result := convertor.ToPointer(123)
fmt.Println(*result) //123 fmt.Println(*result)
// Output:
// 123
} }
``` ```
### <span id="ToString">ToString</span> ### <span id="ToString">ToString</span>
<p>ToString convert value to string, for number, string, []byte, will convert to string. For other type (slice, map, array, struct) will call json.Marshal</p> <p>ToString convert value to string, for number, string, []byte, will convert to string. For other type (slice, map, array, struct) will call json.Marshal</p>
@@ -414,13 +451,33 @@ import (
) )
func main() { func main() {
fmt.Printf("%q", convertor.ToString(1)) //"1" result1 := convertor.ToString("")
fmt.Printf("%q", convertor.ToString(1.1)) //"1.1" result2 := convertor.ToString(nil)
fmt.Printf("%q", convertor.ToString([]int{1, 2, 3})) //"[1,2,3]" result3 := convertor.ToString(0)
result4 := convertor.ToString(1.23)
result5 := convertor.ToString(true)
result6 := convertor.ToString(false)
result7 := convertor.ToString([]int{1, 2, 3})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
//
//
// 0
// 1.23
// true
// false
// [1,2,3]
} }
``` ```
### <span id="StructToMap">StructToMap</span> ### <span id="StructToMap">StructToMap</span>
<p>Convert struct to map, only convert exported field, struct field tag `json` should be set.</p> <p>Convert struct to map, only convert exported field, struct field tag `json` should be set.</p>
@@ -451,7 +508,10 @@ func main() {
} }
pm, _ := convertor.StructToMap(p) pm, _ := convertor.StructToMap(p)
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test] fmt.Println(pm)
// Output:
// map[name:test]
} }
``` ```
@@ -508,12 +568,13 @@ import (
func main() { func main() {
byteData, _ := convertor.EncodeByte("abc") byteData, _ := convertor.EncodeByte("abc")
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99} fmt.Println(byteData)
// Output:
// [6 12 0 3 97 98 99]
} }
``` ```
### <span id="DecodeByte">DecodeByte</span> ### <span id="DecodeByte">DecodeByte</span>
<p>Decode byte data to target object. target should be a pointer instance.</p> <p>Decode byte data to target object. target should be a pointer instance.</p>
@@ -536,7 +597,15 @@ import (
func main() { func main() {
var result string var result string
byteData := []byte{6, 12, 0, 3, 97, 98, 99} byteData := []byte{6, 12, 0, 3, 97, 98, 99}
convertor.DecodeByte(byteData, &result)
fmt.Println(result) //"abc" err := convertor.DecodeByte(byteData, &result)
if err != nil {
return
}
fmt.Println(result)
// Output:
// abc
} }
``` ```
+182 -119
View File
@@ -43,16 +43,15 @@ import (
## 文档 ## 文档
### <span id="ColorHexToRGB">ColorHexToRGB</span> ### <span id="ColorHexToRGB">ColorHexToRGB</span>
<p>颜色值十六进制转rgb</p> <p>颜色值十六进制转rgb</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ColorHexToRGB(colorHex string) (red, green, blue int) func ColorHexToRGB(colorHex string) (red, green, blue int)
``` ```
<b>列子:</b> <b>示例:</b>
```go ```go
package main package main
@@ -65,22 +64,24 @@ import (
func main() { func main() {
colorHex := "#003366" colorHex := "#003366"
r, g, b := convertor.ColorHexToRGB(colorHex) r, g, b := convertor.ColorHexToRGB(colorHex)
fmt.Println(r, g, b) //0,51,102
fmt.Println(r, g, b)
// Output:
// 0 51 102
} }
``` ```
### <span id="ColorRGBToHex">ColorRGBToHex</span> ### <span id="ColorRGBToHex">ColorRGBToHex</span>
<p>颜色值rgb转十六进制</p> <p>颜色值rgb转十六进制</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ColorRGBToHex(red, green, blue int) string func ColorRGBToHex(red, green, blue int) string
``` ```
<b>列子:</b> <b>示例:</b>
```go ```go
package main package main
@@ -94,24 +95,25 @@ func main() {
r := 0 r := 0
g := 51 g := 51
b := 102 b := 102
colorHex := convertor.ColorRGBToHex(r, g, b) colorHex := ColorRGBToHex(r, g, b)
fmt.Println(colorHex) //#003366 fmt.Println(colorHex)
// Output:
// #003366
} }
``` ```
### <span id="ToBool">ToBool</span> ### <span id="ToBool">ToBool</span>
<p>字符串转布尔类型,使用strconv.ParseBool</p> <p>字符串转布尔类型,使用strconv.ParseBool</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToBool(s string) (bool, error) func ToBool(s string) (bool, error)
``` ```
<b>列子:</b> <b>示例:</b>
```go ```go
package main package main
@@ -122,32 +124,36 @@ import (
) )
func main() { func main() {
v1, _ := convertor.ToBool("1") cases := []string{"1", "true", "True", "false", "False", "0", "123", "0.0", "abc"}
fmt.Println(v1) //true
v2, _ := convertor.ToBool("true") for i := 0; i < len(cases); i++ {
fmt.Println(v2) //true result, _ := convertor.ToBool(cases[i])
fmt.Println(result)
}
v3, _ := convertor.ToBool("True") // Output:
fmt.Println(v3) //true // true
// true
v4, _ := convertor.ToBool("123") // true
fmt.Println(v4) //false // false
// false
// false
// false
// false
// false
} }
``` ```
### <span id="ToBytes">ToBytes</span> ### <span id="ToBytes">ToBytes</span>
<p>interface转字节切片.</p> <p>Interface转字节切片</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToBytes(data any) ([]byte, error) func ToBytes(data any) ([]byte, error)
``` ```
<b>列子:</b> <b>示例:</b>
```go ```go
package main package main
@@ -158,26 +164,28 @@ import (
) )
func main() { func main() {
bytesData, err := convertor.ToBytes("0") bytesData, err := convertor.ToBytes("abc")
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
} }
fmt.Println(bytesData) //[]bytes{3, 4, 0, 0}
fmt.Println(bytesData)
// Output:
// [97 98 99]
} }
``` ```
### <span id="ToChar">ToChar</span> ### <span id="ToChar">ToChar</span>
<p>字符串转字符切片</p> <p>字符串转字符切片</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToChar(s string) []string func ToChar(s string) []string
``` ```
<b>列子:</b> <b>示例:</b>
```go ```go
package main package main
@@ -188,29 +196,31 @@ import (
) )
func main() { func main() {
chars := convertor.ToChar("") result1 := convertor.ToChar("")
fmt.Println(chars) //[]string{""} result2 := convertor.ToChar("abc")
result3 := convertor.ToChar("1 2#3")
chars = convertor.ToChar("abc") fmt.Println(result1)
fmt.Println(chars) //[]string{"a", "b", "c"} fmt.Println(result2)
fmt.Println(result3)
chars = convertor.ToChar("1 2#3") // Output:
fmt.Println(chars) //[]string{"1", " ", "2", "#", "3"} // []
// [a b c]
// [1 2 # 3]
} }
``` ```
### <span id="ToChannel">ToChannel</span> ### <span id="ToChannel">ToChannel</span>
<p>将切片转为只读channel</p> <p>将切片转为只读channel</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToChannel[T any](array []T) <-chan T func ToChannel[T any](array []T) <-chan T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -222,33 +232,31 @@ import (
func main() { func main() {
ch := convertor.ToChannel([]int{1, 2, 3}) ch := convertor.ToChannel([]int{1, 2, 3})
result1 := <-ch
result2 := <-ch
result3 := <-ch
val1, _ := <-ch fmt.Println(result1)
fmt.Println(val1) //1 fmt.Println(result2)
fmt.Println(result3)
val2, _ := <-ch // Output:
fmt.Println(val2) //2 // 1
// 2
val3, _ := <-ch // 3
fmt.Println(val3) //3
_, ok := <-ch
fmt.Println(ok) //false
} }
``` ```
### <span id="ToFloat">ToFloat</span> ### <span id="ToFloat">ToFloat</span>
<p>将interface转成float64类型,如果参数无法转换,会返回0和error</p> <p>将interface转成float64类型,如果参数无法转换,会返回0和error</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToFloat(value any) (float64, error) func ToFloat(value any) (float64, error)
``` ```
<b>列子:</b> <b>示例:</b>
```go ```go
package main package main
@@ -259,29 +267,40 @@ import (
) )
func main() { func main() {
v, err := convertor.ToFloat("") result1, _ := convertor.ToFloat("")
if err != nil { result2, err := convertor.ToFloat("abc")
fmt.Println(err) //strconv.ParseFloat: parsing "": invalid syntax result3, _ := convertor.ToFloat("-1")
} result4, _ := convertor.ToFloat("-.11")
fmt.Println(v) //0 result5, _ := convertor.ToFloat("1.23e3")
result6, _ := convertor.ToFloat(true)
v, _ = convertor.ToFloat("-.11") fmt.Println(result1)
fmt.Println(v) //-0.11 fmt.Println(result2, err)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// 0
// 0 strconv.ParseFloat: parsing "": invalid syntax
// -1
// -0.11
// 1230
// 0
} }
``` ```
### <span id="ToInt">ToInt</span> ### <span id="ToInt">ToInt</span>
<p>将interface转成int64类型,如果参数无法转换,会返回0和error</p> <p>将interface转成int64类型,如果参数无法转换,会返回0和error</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToInt(value any) (int64, error) func ToInt(value any) (int64, error)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -292,29 +311,37 @@ import (
) )
func main() { func main() {
v, err := convertor.ToInt("") result1, _ := convertor.ToInt("123")
if err != nil { result2, _ := convertor.ToInt("-123")
fmt.Println(err) //strconv.ParseInt: parsing "": invalid syntax result3, _ := convertor.ToInt(float64(12.3))
} result4, err := convertor.ToInt("abc")
fmt.Println(v) //0 result5, _ := convertor.ToInt(true)
v, _ = convertor.ToFloat(1.12) fmt.Println(result1)
fmt.Println(v) //1 fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4, err)
fmt.Println(result5)
// Output:
// 123
// -123
// 12
// 0 strconv.ParseInt: parsing "": invalid syntax
// 0
} }
``` ```
### <span id="ToJson">ToJson</span> ### <span id="ToJson">ToJson</span>
<p>将interface转成json字符串,如果参数无法转换,会返回""和error</p> <p>将interface转成json字符串,如果参数无法转换,会返回""和error</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToJson(value any) (string, error) func ToJson(value any) (string, error)
``` ```
<b>列子:</b> <b>示例:</b>
```go ```go
package main package main
@@ -325,24 +352,30 @@ import (
) )
func main() { func main() {
var aMap = map[string]int{"a": 1, "b": 2, "c": 3} aMap := map[string]int{"a": 1, "b": 2, "c": 3}
jsonStr, _ := convertor.ToJson(aMap) result, err := ToJson(aMap)
fmt.Printf("%q", jsonStr) //"{\"a\":1,\"b\":2,\"c\":3}"
if err != nil {
fmt.Printf("%v", err)
}
fmt.Println(result)
// Output:
// {"a":1,"b":2,"c":3}
} }
``` ```
### <span id="ToMap">ToMap</span> ### <span id="ToMap">ToMap</span>
<p>将切片转为map</p> <p>将切片转为map</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
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
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -361,26 +394,28 @@ func main() {
{name: "Hello", code: 100}, {name: "Hello", code: 100},
{name: "Hi", code: 101}, {name: "Hi", code: 101},
} }
result := convertor.ToMap(messages, func(msg Message) (int, string) { result := convertor.ToMap(messages, func(msg Message) (int, string) {
return msg.code, msg.name return msg.code, msg.name
}) })
fmt.Println(result) //{100: "Hello", 101: "Hi"} fmt.Println(result)
// Output:
// map[100:Hello 101:Hi]
} }
``` ```
### <span id="ToPointer">ToPointer</span> ### <span id="ToPointer">ToPointer</span>
<p>返回传入值的指针</p> <p>返回传入值的指针</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToPointer[T any](value T) *T func ToPointer[T any](value T) *T
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -392,22 +427,23 @@ import (
func main() { func main() {
result := convertor.ToPointer(123) result := convertor.ToPointer(123)
fmt.Println(*result) //123 fmt.Println(*result)
// Output:
// 123
} }
``` ```
### <span id="ToString">ToString</span> ### <span id="ToString">ToString</span>
<p>将值转换为字符串,对于数字、字符串、[]byte,将转换为字符串。 对于其他类型(切片、映射、数组、结构)将调用 json.Marshal</p> <p>将值转换为字符串,对于数字、字符串、[]byte,将转换为字符串。 对于其他类型(切片、映射、数组、结构)将调用 json.Marshal</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func ToString(value any) string func ToString(value any) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -418,24 +454,43 @@ import (
) )
func main() { func main() {
fmt.Printf("%q", convertor.ToString(1)) //"1" result1 := convertor.ToString("")
fmt.Printf("%q", convertor.ToString(1.1)) //"1.1" result2 := convertor.ToString(nil)
fmt.Printf("%q", convertor.ToString([]int{1, 2, 3})) //"[1,2,3]" result3 := convertor.ToString(0)
result4 := convertor.ToString(1.23)
result5 := convertor.ToString(true)
result6 := convertor.ToString(false)
result7 := convertor.ToString([]int{1, 2, 3})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
// Output:
//
//
// 0
// 1.23
// true
// false
// [1,2,3]
} }
``` ```
### <span id="StructToMap">StructToMap</span> ### <span id="StructToMap">StructToMap</span>
<p>将struct转成map,只会转换struct中可导出的字段。struct中导出字段需要设置json tag标记</p> <p>将struct转成map,只会转换struct中可导出的字段。struct中导出字段需要设置json tag标记</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func StructToMap(value any) (map[string]any, error) func StructToMap(value any) (map[string]any, error)
``` ```
<b>列子:</b> <b>示例:</b>
```go ```go
package main package main
@@ -456,22 +511,23 @@ func main() {
} }
pm, _ := convertor.StructToMap(p) pm, _ := convertor.StructToMap(p)
fmt.Printf("type: %T, value: %s", pm, pm) //type: map[string]interface {}, value: map[name:test] fmt.Println(pm)
// Output:
// map[name:test]
} }
``` ```
### <span id="MapToSlice">MapToSlice</span> ### <span id="MapToSlice">MapToSlice</span>
<p>map中key和value执行函数iteratee后,转为切片</p> <p>map中key和value执行函数iteratee后,转为切片</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
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
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -491,18 +547,16 @@ func main() {
} }
``` ```
### <span id="EncodeByte">EncodeByte</span> ### <span id="EncodeByte">EncodeByte</span>
<p>将data编码成字节切片</p> <p>将data编码成字节切片</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func EncodeByte(data any) ([]byte, error) func EncodeByte(data any) ([]byte, error)
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -514,22 +568,23 @@ import (
func main() { func main() {
byteData, _ := convertor.EncodeByte("abc") byteData, _ := convertor.EncodeByte("abc")
fmt.Println(byteData) //[]byte{6, 12, 0, 3, 97, 98, 99} fmt.Println(byteData)
// Output:
// [6 12 0 3 97 98 99]
} }
``` ```
### <span id="DecodeByte">DecodeByte</span> ### <span id="DecodeByte">DecodeByte</span>
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例</p> <p>解码字节切片到目标对象,目标对象需要传入一个指针实例</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func DecodeByte(data []byte, target any) error func DecodeByte(data []byte, target any) error
``` ```
<b>例:</b> <b>例:</b>
```go ```go
package main package main
@@ -542,7 +597,15 @@ import (
func main() { func main() {
var result string var result string
byteData := []byte{6, 12, 0, 3, 97, 98, 99} byteData := []byte{6, 12, 0, 3, 97, 98, 99}
convertor.DecodeByte(byteData, &result)
fmt.Println(result) //"abc" err := convertor.DecodeByte(byteData, &result)
if err != nil {
return
}
fmt.Println(result)
// Output:
// abc
} }
``` ```
+220 -146
View File
@@ -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>
@@ -61,8 +61,6 @@ import (
## Documentation ## Documentation
### <span id="AesEcbEncrypt">AesEcbEncrypt</span> ### <span id="AesEcbEncrypt">AesEcbEncrypt</span>
<p>Encrypt data with key use AES ECB algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Encrypt data with key use AES ECB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -83,16 +81,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted)) encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesEcbDecrypt">AesEcbDecrypt</span> ### <span id="AesEcbDecrypt">AesEcbDecrypt</span>
<p>Decrypt data with key use AES ECB algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Decrypt data with key use AES ECB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -113,16 +114,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key)) encrypted := cryptor.AesEcbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key)) decrypted := cryptor.AesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesCbcEncrypt">AesCbcEncrypt</span> ### <span id="AesCbcEncrypt">AesCbcEncrypt</span>
<p>Encrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Encrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -143,16 +147,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted)) encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesCbcDecrypt">AesCbcDecrypt</span> ### <span id="AesCbcDecrypt">AesCbcDecrypt</span>
<p>Decrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Decrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -174,16 +181,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key)) encrypted := cryptor.AesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key)) decrypted := cryptor.AesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesCtrCrypt">AesCtrCrypt</span> ### <span id="AesCtrCrypt">AesCtrCrypt</span>
<p>Encrypt or decrypt data with key use AES CTR algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Encrypt or decrypt data with key use AES CTR algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -205,17 +215,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesCtrCrypt([]byte(data), []byte(key)) encrypted := cryptor.AesCtrCrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCtrCrypt(encrypted, []byte(key)) decrypted := cryptor.AesCtrCrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesCfbEncrypt">AesCfbEncrypt</span> ### <span id="AesCfbEncrypt">AesCfbEncrypt</span>
<p>Encrypt data with key use AES CFB algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Encrypt data with key use AES CFB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -237,15 +249,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key)) encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted)) decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesCfbDecrypt">AesCfbDecrypt</span> ### <span id="AesCfbDecrypt">AesCfbDecrypt</span>
<p>Decrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Decrypt data with key use AES CBC algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -267,16 +283,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key)) encrypted := cryptor.AesCfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key)) decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesOfbEncrypt">AesOfbEncrypt</span> ### <span id="AesOfbEncrypt">AesOfbEncrypt</span>
<p>Enecrypt data with key use AES OFB algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Enecrypt data with key use AES OFB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -298,15 +317,18 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key)) encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted)) decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="AesCfbDecrypt">AesOfbDecrypt</span> ### <span id="AesCfbDecrypt">AesOfbDecrypt</span>
<p>Decrypt data with key use AES OFB algorithm. Length of `key` param should be 16, 24 or 32.</p> <p>Decrypt data with key use AES OFB algorithm. Length of `key` param should be 16, 24 or 32.</p>
@@ -328,17 +350,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefghijklmnop" key := "abcdefghijklmnop"
encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world encrypted := cryptor.AesOfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.AesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="Base64StdEncode">Base64StdEncode</span> ### <span id="Base64StdEncode">Base64StdEncode</span>
<p>Encode string with base64 encoding.</p> <p>Encode string with base64 encoding.</p>
@@ -359,13 +383,13 @@ import (
) )
func main() { func main() {
base64Str := cryptor.Base64StdEncode("hello world") base64Str := cryptor.Base64StdEncode("hello")
fmt.Println(base64Str) //aGVsbG8gd29ybGQ= fmt.Println(base64Str)
// Output:
// aGVsbG8=
} }
``` ```
### <span id="Base64StdDecode">Base64StdDecode</span> ### <span id="Base64StdDecode">Base64StdDecode</span>
<p>Decode a base64 encoded string.</p> <p>Decode a base64 encoded string.</p>
@@ -387,13 +411,14 @@ import (
) )
func main() { func main() {
str := cryptor.Base64StdDecode("aGVsbG8gd29ybGQ=") str := cryptor.Base64StdDecode("aGVsbG8=")
fmt.Println(str) //hello world fmt.Println(str)
// Output:
// hello
} }
``` ```
### <span id="DesEcbEncrypt">DesEcbEncrypt</span> ### <span id="DesEcbEncrypt">DesEcbEncrypt</span>
<p>Encrypt data with key use DES ECB algorithm. Length of `key` param should be 8.</p> <p>Encrypt data with key use DES ECB algorithm. Length of `key` param should be 8.</p>
@@ -415,16 +440,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byte(key)) encrypted := cryptor.DesEcbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted)) decrypted := cryptor.DesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesEcbDecrypt">DesEcbDecrypt</span> ### <span id="DesEcbDecrypt">DesEcbDecrypt</span>
<p>Decrypt data with key use DES ECB algorithm. Length of `key` param should be 8.</p> <p>Decrypt data with key use DES ECB algorithm. Length of `key` param should be 8.</p>
@@ -446,17 +474,20 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byt(key)
encrypted := cryptor.DesEcbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesEcbDecrypt(encrypted, []byte(key)) decrypted := cryptor.DesEcbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesCbcEncrypt">DesCbcEncrypt</span> ### <span id="DesCbcEncrypt">DesCbcEncrypt</span>
<p>Encrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p> <p>Encrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p>
@@ -478,16 +509,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byt(key)
fmt.Println(string(encrypted)) encrypted := cryptor.DesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesCbcDecrypt">DesCbcDecrypt</span> ### <span id="DesCbcDecrypt">DesCbcDecrypt</span>
<p>Decrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p> <p>Decrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p>
@@ -509,17 +543,18 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byt(key)
encrypted := cryptor.DesCbcEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCbcDecrypt(encrypted, []byte(key)) decrypted := cryptor.DesCbcDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesCtrCrypt">DesCtrCrypt</span> ### <span id="DesCtrCrypt">DesCtrCrypt</span>
<p>Encrypt or decrypt data with key use DES CTR algorithm. Length of `key` param should be 8.</p> <p>Encrypt or decrypt data with key use DES CTR algorithm. Length of `key` param should be 8.</p>
@@ -541,17 +576,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesCtrCrypt([]byte(data), []byte(key)) encrypted := cryptor.DesCtrCrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCtrCrypt(encrypted, []byte(key)) decrypted := cryptor.DesCtrCrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesCfbEncrypt">DesCfbEncrypt</span> ### <span id="DesCfbEncrypt">DesCfbEncrypt</span>
<p>Encrypt data with key use DES CFB algorithm. Length of `key` param should be 8.</p> <p>Encrypt data with key use DES CFB algorithm. Length of `key` param should be 8.</p>
@@ -573,15 +610,18 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byt(key)
fmt.Println(string(encrypted)) encrypted := cryptor.DesCfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesCfbDecrypt">DesCfbDecrypt</span> ### <span id="DesCfbDecrypt">DesCfbDecrypt</span>
<p>Decrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p> <p>Decrypt data with key use DES CBC algorithm. Length of `key` param should be 8.</p>
@@ -603,16 +643,18 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byt(key)
encrypted := cryptor.DesCfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesCfbDecrypt(encrypted, []byte(key)) decrypted := cryptor.DesCfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesOfbEncrypt">DesOfbEncrypt</span> ### <span id="DesOfbEncrypt">DesOfbEncrypt</span>
<p>Enecrypt data with key use DES OFB algorithm. Length of `key` param should be 8.</p> <p>Enecrypt data with key use DES OFB algorithm. Length of `key` param should be 8.</p>
@@ -634,15 +676,18 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key)) encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key))
fmt.Println(string(encrypted)) decrypted := cryptor.DesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="DesOfbDecrypt">DesOfbDecrypt</span> ### <span id="DesOfbDecrypt">DesOfbDecrypt</span>
<p>Decrypt data with key use DES OFB algorithm. Length of `key` param should be 8.</p> <p>Decrypt data with key use DES OFB algorithm. Length of `key` param should be 8.</p>
@@ -664,17 +709,19 @@ import (
) )
func main() { func main() {
data := "hello world" data := "hello"
key := "abcdefgh" key := "abcdefgh"
encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key)) encrypted := cryptor.DesOfbEncrypt([]byte(data), []byte(key))
decrypted := cryptor.DesOfbDecrypt(encrypted, []byte(key)) decrypted := cryptor.DesOfbDecrypt(encrypted, []byte(key))
fmt.Println(string(decrypted)) //hello world fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="HmacMd5">HmacMd5</span> ### <span id="HmacMd5">HmacMd5</span>
<p>Get the md5 hmac hash of string.</p> <p>Get the md5 hmac hash of string.</p>
@@ -696,13 +743,16 @@ import (
) )
func main() { func main() {
s := cryptor.HmacMd5("hello world", "12345")) str := "hello"
fmt.Println(s) //5f4c9faaff0a1ad3007d9ddc06abe36d key := "12345"
hms := cryptor.HmacMd5(str, key)
fmt.Println(hms)
// Output:
// e834306eab892d872525d4918a7a639a
} }
``` ```
### <span id="HmacSha1">HmacSha1</span> ### <span id="HmacSha1">HmacSha1</span>
<p>Get the sha1 hmac hash of string.</p> <p>Get the sha1 hmac hash of string.</p>
@@ -724,13 +774,16 @@ import (
) )
func main() { func main() {
s := cryptor.HmacSha1("hello world", "12345")) str := "hello"
fmt.Println(s) //3826f812255d8683f051ee97346d1359234d5dbd key := "12345"
hms := cryptor.HmacSha1(str, key)
fmt.Println(hms)
// Output:
// 5c6a9db0cccb92e36ed0323fd09b7f936de9ace0
} }
``` ```
### <span id="HmacSha256">HmacSha256</span> ### <span id="HmacSha256">HmacSha256</span>
<p>Get the sha256 hmac hash of string</p> <p>Get the sha256 hmac hash of string</p>
@@ -752,13 +805,17 @@ import (
) )
func main() { func main() {
s := cryptor.HmacSha256("hello world", "12345")) str := "hello"
fmt.Println(s) //9dce2609f2d67d41f74c7f9efc8ccd44370d41ad2de52982627588dfe7289ab8 key := "12345"
hms := cryptor.HmacSha256(str, key)
fmt.Println(hms)
// Output:
// 315bb93c4e989862ba09cb62e05d73a5f376cb36f0d786edab0c320d059fde75
} }
``` ```
### <span id="HmacSha512">HmacSha512</span> ### <span id="HmacSha512">HmacSha512</span>
<p>Get the sha512 hmac hash of string.</p> <p>Get the sha512 hmac hash of string.</p>
@@ -780,14 +837,18 @@ import (
) )
func main() { func main() {
s := cryptor.HmacSha512("hello world", "12345")) str := "hello"
fmt.Println(s) key := "12345"
//5b1563ac4e9b49c9ada8ccb232588fc4f0c30fd12f756b3a0b95af4985c236ca60925253bae10ce2c6bf9af1c1679b51e5395ff3d2826c0a2c7c0d72225d4175
hms := cryptor.HmacSha512(str, key)
fmt.Println(hms)
// Output:
// dd8f1290a9dd23d354e2526d9a2e9ce8cffffdd37cb320800d1c6c13d2efc363288376a196c5458daf53f8e1aa6b45a6d856303d5c0a2064bff9785861d48cfc
} }
``` ```
### <span id="Md5String">Md5String</span> ### <span id="Md5String">Md5String</span>
<p>Get the md5 value of string.</p> <p>Get the md5 value of string.</p>
@@ -809,13 +870,16 @@ import (
) )
func main() { func main() {
s := cryptor.Md5String("hello")) str := "hello"
fmt.Println(s) //5d41402abc4b2a76b9719d911017c592
md5Str := cryptor.Md5String(str)
fmt.Println(md5Str)
// Output:
// 5d41402abc4b2a76b9719d911017c592
} }
``` ```
### <span id="Md5File">Md5File</span> ### <span id="Md5File">Md5File</span>
<p>Get the md5 value of file.</p> <p>Get the md5 value of file.</p>
@@ -842,8 +906,6 @@ func main() {
} }
``` ```
### <span id="Sha1">Sha1</span> ### <span id="Sha1">Sha1</span>
<p>Get the sha1 value of string.</p> <p>Get the sha1 value of string.</p>
@@ -865,13 +927,16 @@ import (
) )
func main() { func main() {
s := cryptor.Sha1("hello world")) str := "hello"
fmt.Println(s) //2aae6c35c94fcfb415dbe95f408b9ce91ee846ed
result := cryptor.Sha1(str)
fmt.Println(result)
// Output:
// aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
} }
``` ```
### <span id="Sha256">Sha256</span> ### <span id="Sha256">Sha256</span>
<p>Get the sha256 value of string.</p> <p>Get the sha256 value of string.</p>
@@ -893,13 +958,16 @@ import (
) )
func main() { func main() {
s := cryptor.Sha256("hello world")) str := "hello"
fmt.Println(s) //b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
result := cryptor.Sha256(str)
fmt.Println(result)
// Output:
// 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
} }
``` ```
### <span id="Sha512">Sha512</span> ### <span id="Sha512">Sha512</span>
<p>Get the sha512 value of string.</p> <p>Get the sha512 value of string.</p>
@@ -921,13 +989,16 @@ import (
) )
func main() { func main() {
s := cryptor.Sha512("hello world")) str := "hello"
fmt.Println(s) //309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f
result := cryptor.Sha512(str)
fmt.Println(result)
// Output:
// 9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043
} }
``` ```
### <span id="GenerateRsaKey">GenerateRsaKey</span> ### <span id="GenerateRsaKey">GenerateRsaKey</span>
<p>Create the rsa public and private key file in current directory.</p> <p>Create the rsa public and private key file in current directory.</p>
@@ -956,8 +1027,6 @@ func main() {
} }
``` ```
### <span id="RsaEncrypt">RsaEncrypt</span> ### <span id="RsaEncrypt">RsaEncrypt</span>
<p>Encrypt data with public key file useing ras algorithm.</p> <p>Encrypt data with public key file useing ras algorithm.</p>
@@ -981,19 +1050,21 @@ import (
func main() { func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem") err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil { if err != nil {
fmt.Println(err) return
} }
data := []byte("hello world") data := []byte("hello")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem") encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem") decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted)) //hello world fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
### <span id="RsaDecrypt">RsaDecrypt</span> ### <span id="RsaDecrypt">RsaDecrypt</span>
<p>Decrypt data with private key file useing ras algorithm.</p> <p>Decrypt data with private key file useing ras algorithm.</p>
@@ -1017,14 +1088,17 @@ import (
func main() { func main() {
err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem") err := cryptor.GenerateRsaKey(4096, "rsa_private.pem", "rsa_public.pem")
if err != nil { if err != nil {
fmt.Println(err) return
} }
data := []byte("hello world") data := []byte("hello")
encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem") encrypted := cryptor.RsaEncrypt(data, "rsa_public.pem")
decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem") decrypted := cryptor.RsaDecrypt(encrypted, "rsa_private.pem")
fmt.Println(string(decrypted)) //hello world fmt.Println(string(decrypted))
// Output:
// hello
} }
``` ```
+281 -205
View File
File diff suppressed because it is too large Load Diff
@@ -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}
} }
``` ```
+4 -4
View File
@@ -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>
+2 -2
View File
@@ -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>
+2 -3
View File
@@ -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>
+2 -2
View File
@@ -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>
+27 -26
View File
@@ -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,11 +149,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
} }
``` ```
@@ -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() {
+27 -25
View File
@@ -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() {
+6 -6
View File
@@ -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
} }
``` ```
+5 -5
View File
@@ -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
} }
``` ```
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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>
+6 -6
View File
@@ -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>
+366 -203
View File
@@ -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>
@@ -61,21 +64,29 @@ import (
) )
func main() { func main() {
s1 := strutil.After("lancet", "") result1 := strutil.After("foo", "")
fmt.Println(s1) //lancet result2 := strutil.After("foo", "foo")
result3 := strutil.After("foo/bar", "foo")
result4 := strutil.After("foo/bar", "/")
result5 := strutil.After("foo/bar/baz", "/")
s2 := strutil.After("github.com/test/lancet", "/") fmt.Println(result1)
fmt.Println(s2) //test/lancet fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
s3 := strutil.After("github.com/test/lancet", "test") // Output:
fmt.Println(s3) // /lancet // foo
//
// /bar
// bar
// bar/baz
} }
``` ```
### <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>
@@ -91,22 +102,29 @@ import (
) )
func main() { func main() {
s1 := strutil.AfterLast("lancet", "") result1 := strutil.AfterLast("foo", "")
fmt.Println(s1) //lancet result2 := strutil.AfterLast("foo", "foo")
result3 := strutil.AfterLast("foo/bar", "/")
result4 := strutil.AfterLast("foo/bar/baz", "/")
result5 := strutil.AfterLast("foo/bar/foo/baz", "foo")
s2 := strutil.AfterLast("github.com/test/lancet", "/") fmt.Println(result1)
fmt.Println(s2) //lancet fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
s3 := strutil.AfterLast("github.com/test/test/lancet", "test") // Output:
fmt.Println(s3) // /test/lancet // foo
//
// bar
// baz
// /baz
} }
``` ```
### <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>
@@ -122,22 +140,26 @@ import (
) )
func main() { func main() {
s1 := strutil.Before("lancet", "") result1 := strutil.Before("foo", "")
fmt.Println(s1) //lancet result2 := strutil.Before("foo", "foo")
result3 := strutil.Before("foo/bar", "/")
result4 := strutil.Before("foo/bar/baz", "/")
s2 := strutil.Before("github.com/test/lancet", "/") fmt.Println(result1)
fmt.Println(s2) //github.com fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
s3 := strutil.Before("github.com/test/lancet", "test") // Output:
fmt.Println(s3) // github.com/ // foo
//
// foo
// foo
} }
``` ```
### <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>
@@ -153,22 +175,26 @@ import (
) )
func main() { func main() {
s1 := strutil.BeforeLast("lancet", "") result1 := strutil.BeforeLast("foo", "")
fmt.Println(s1) //lancet result2 := strutil.BeforeLast("foo", "foo")
result3 := strutil.BeforeLast("foo/bar", "/")
result4 := strutil.BeforeLast("foo/bar/baz", "/")
s2 := strutil.BeforeLast("github.com/test/lancet", "/") fmt.Println(result1)
fmt.Println(s2) //github.com/test fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
s3 := strutil.BeforeLast("github.com/test/test/lancet", "test") // Output:
fmt.Println(s3) //github.com/test/ // foo
//
// foo
// foo/bar
} }
``` ```
### <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>
@@ -184,22 +210,87 @@ import (
) )
func main() { func main() {
s1 := strutil.CamelCase("foo_bar") strings := []string{"", "foobar", "&FOO:BAR$BAZ", "$foo%", "Foo-#1😄$_%^&*(1bar"}
fmt.Println(s1) //fooBar
s2 := strutil.CamelCase("Foo-Bar") for _, v := range strings {
fmt.Println(s2) //fooBar s := strutil.CamelCase(v)
fmt.Println(s)
}
s3 := strutil.CamelCase("Foo&bar") // Output:
fmt.Println(s3) //fooBar //
// foobar
s4 := strutil.CamelCase("foo bar") // fooBarBaz
fmt.Println(s4) //fooBar // foo
// 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() {
strings := []string{"", "foo-bar", "Foo Bar-", "FOOBAR", "Foo-#1😄$_%^&*(1bar"}
for _, v := range strings {
s := strutil.KebabCase(v)
fmt.Println(s)
}
// Output:
//
// foo-bar
// foo-bar
// foobar
// foo-1-1-bar
}
```
### <span id="UpperKebabCase">UpperKebabCase</span>
<p>UpperKebabCase covert string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
<b>Signature:</b>
```go
func UpperKebabCase(s string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
strings := []string{"", "foo-bar", "Foo Bar-", "FooBAR", "Foo-#1😄$_%^&*(1bar"}
for _, v := range strings {
s := strutil.UpperKebabCase(v)
fmt.Println(s)
}
// Output:
//
// FOO-BAR
// FOO-BAR
// FOO-BAR
// FOO-1-1-BAR
}
```
### <span id="Capitalize">Capitalize</span> ### <span id="Capitalize">Capitalize</span>
<p>Convert the first character of a string to upper case.</p> <p>Convert the first character of a string to upper case.</p>
@@ -218,19 +309,22 @@ import (
) )
func main() { func main() {
s1 := strutil.Capitalize("foo") strings := []string{"", "Foo", "_foo", "fooBar", "foo-bar"}
fmt.Println(s1) //foo
s2 := strutil.Capitalize("Foo") for _, v := range strings {
fmt.Println(s2) //foo s := strutil.Capitalize(v)
fmt.Println(s)
}
s3 := strutil.Capitalize("FOo" // Output:
fmt.Println(s3) //fOo //
// Foo
// _foo
// Foobar
// Foo-bar
} }
``` ```
### <span id="IsString">IsString</span> ### <span id="IsString">IsString</span>
<p>Check if the value's data type is string.</p> <p>Check if the value's data type is string.</p>
@@ -248,51 +342,27 @@ import (
) )
func main() { func main() {
fmt.Println(strutil.IsString("lancet")) //true result1 := strutil.IsString("")
fmt.Println(strutil.IsString("")) //true result2 := strutil.IsString("a")
result3 := strutil.IsString(1)
result4 := strutil.IsString(true)
result5 := strutil.IsString([]string{"a"})
fmt.Println(strutil.IsString(1)) //false fmt.Println(result1)
fmt.Println(strutil.IsString("")) //false fmt.Println(result2)
fmt.Println(strutil.IsString([]string{})) //false fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// true
// true
// false
// false
// false
} }
``` ```
### <span id="KebabCase">KebabCase</span>
<p>Covert string to kebab-case.</p>
<b>Signature:</b>
```go
func KebabCase(s string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.KebabCase("Foo Bar-")
fmt.Println(s1) //foo-bar
s2 := strutil.KebabCase("foo_Bar")
fmt.Println(s2) //foo-bar
s3 := strutil.KebabCase("fooBar")
fmt.Println(s3) //foo-bar
s4 := strutil.KebabCase("__FOO_BAR__")
fmt.Println(s4) //f-o-o-b-a-r
}
```
### <span id="LowerFirst">LowerFirst</span> ### <span id="LowerFirst">LowerFirst</span>
<p>Convert the first character of string to lower case.</p> <p>Convert the first character of string to lower case.</p>
@@ -310,23 +380,21 @@ import (
) )
func main() { func main() {
s1 := strutil.LowerFirst("foo") strings := []string{"", "bar", "BAr", "Bar大"}
fmt.Println(s1) //foo
s2 := strutil.LowerFirst("BAR") for _, v := range strings {
fmt.Println(s2) //bAR s := strutil.LowerFirst(v)
fmt.Println(s)
}
s3 := strutil.LowerFirst("FOo") // Output:
fmt.Println(s3) //fOo //
// bar
s4 := strutil.LowerFirst("fOo大") // bAr
fmt.Println(s4) //fOo // bar
} }
``` ```
### <span id="UpperFirst">UpperFirst</span> ### <span id="UpperFirst">UpperFirst</span>
<p>Convert the first character of string to upper case.</p> <p>Convert the first character of string to upper case.</p>
@@ -344,23 +412,21 @@ import (
) )
func main() { func main() {
s1 := strutil.UpperFirst("foo") strings := []string{"", "bar", "BAr", "bar大"}
fmt.Println(s1) //Foo
s2 := strutil.UpperFirst("bAR") for _, v := range strings {
fmt.Println(s2) //BAR s := strutil.UpperFirst(v)
fmt.Println(s)
}
s3 := strutil.UpperFirst("FOo") // Output:
fmt.Println(s3) //FOo //
// Bar
s4 := strutil.UpperFirst("fOo大") // BAr
fmt.Println(s4) //FOo // Bar
} }
``` ```
### <span id="PadEnd">PadEnd</span> ### <span id="PadEnd">PadEnd</span>
<p>Pads string on the right side if it's shorter than size.</p> <p>Pads string on the right side if it's shorter than size.</p>
@@ -378,23 +444,33 @@ import (
) )
func main() { func main() {
s1 := strutil.PadEnd("a", 1, "b") result1 := strutil.PadEnd("foo", 1, "bar")
fmt.Println(s1) //a result2 := strutil.PadEnd("foo", 2, "bar")
result3 := strutil.PadEnd("foo", 3, "bar")
result4 := strutil.PadEnd("foo", 4, "bar")
result5 := strutil.PadEnd("foo", 5, "bar")
result6 := strutil.PadEnd("foo", 6, "bar")
result7 := strutil.PadEnd("foo", 7, "bar")
s2 := strutil.PadEnd("a", 2, "b") fmt.Println(result1)
fmt.Println(s2) //ab fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
s3 := strutil.PadEnd("abcd", 6, "mno") // Output:
fmt.Println(s3) //abcdmn // foo
// foo
s4 := strutil.PadEnd("abc", 6, "ab") // foo
fmt.Println(s4) //abcaba // foob
// fooba
// foobar
// foobarb
} }
``` ```
### <span id="PadStart">PadStart</span> ### <span id="PadStart">PadStart</span>
<p>Pads string on the left side if it's shorter than size.</p> <p>Pads string on the left side if it's shorter than size.</p>
@@ -412,23 +488,33 @@ import (
) )
func main() { func main() {
s1 := strutil.PadStart("a", 1, "b") result1 := strutil.PadStart("foo", 1, "bar")
fmt.Println(s1) //a result2 := strutil.PadStart("foo", 2, "bar")
result3 := strutil.PadStart("foo", 3, "bar")
result4 := strutil.PadStart("foo", 4, "bar")
result5 := strutil.PadStart("foo", 5, "bar")
result6 := strutil.PadStart("foo", 6, "bar")
result7 := strutil.PadStart("foo", 7, "bar")
s2 := strutil.PadStart("a", 2, "b") fmt.Println(result1)
fmt.Println(s2) //ba fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
s3 := strutil.PadStart("abcd", 6, "mno") // Output:
fmt.Println(s3) //mnabcd // foo
// foo
s4 := strutil.PadStart("abc", 6, "ab") // foo
fmt.Println(s4) //abaabc // bfoo
// bafoo
// barfoo
// barbfoo
} }
``` ```
### <span id="Reverse">Reverse</span> ### <span id="Reverse">Reverse</span>
<p>Return string whose char order is reversed to the given string.</p> <p>Return string whose char order is reversed to the given string.</p>
@@ -446,18 +532,20 @@ import (
) )
func main() { func main() {
s1 := strutil.ReverseStr("abc") s := "foo"
fmt.Println(s1) //cba rs := strutil.Reverse(s)
s2 := strutil.ReverseStr("12345") fmt.Println(s)
fmt.Println(s2) //54321 fmt.Println(rs)
// Output:
// foo
// oof
} }
``` ```
### <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>
@@ -473,25 +561,54 @@ import (
) )
func main() { func main() {
s1 := strutil.SnakeCase("Foo Bar-") strings := []string{"", "foo-bar", "Foo Bar-", "FOOBAR", "Foo-#1😄$_%^&*(1bar"}
fmt.Println(s1) //foo_bar
s2 := strutil.SnakeCase("foo_Bar") for _, v := range strings {
fmt.Println(s2) //foo_bar s := strutil.SnakeCase(v)
fmt.Println(s)
}
s3 := strutil.SnakeCase("fooBar") // Output:
fmt.Println(s3) //foo_bar //
// foo_bar
s4 := strutil.SnakeCase("__FOO_BAR__") // foo_bar
fmt.Println(s4) //f_o_o_b_a_r // foobar
// foo_1_1_bar
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
fmt.Println(s5) //a_bbc_s_a_b_b_c
} }
``` ```
### <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() {
strings := []string{"", "foo-bar", "Foo Bar-", "FooBAR", "Foo-#1😄$_%^&*(1bar"}
for _, v := range strings {
s := strutil.UpperSnakeCase(v)
fmt.Println(s)
}
// Output:
//
// FOO_BAR
// FOO_BAR
// FOO_BAR
// FOO_1_1_BAR
}
```
### <span id="SplitEx">SplitEx</span> ### <span id="SplitEx">SplitEx</span>
<p>Split a given string whether the result contains empty string.</p> <p>Split a given string whether the result contains empty string.</p>
@@ -510,28 +627,71 @@ import (
) )
func main() { func main() {
arr1 := strutil.SplitEx(" a b c ", "", true) result1 := strutil.SplitEx(" a b c ", "", true)
fmt.Println(arr1) //[]string{}
arr2 := strutil.SplitEx(" a b c ", " ", false) result2 := strutil.SplitEx(" a b c ", " ", false)
fmt.Println(arr2) //[]string{"", "a", "b", "c", ""} result3 := strutil.SplitEx(" a b c ", " ", true)
arr3 := strutil.SplitEx(" a b c ", " ", true) result4 := strutil.SplitEx("a = b = c = ", " = ", false)
fmt.Println(arr3) //[]string{"a", "b", "c"} result5 := strutil.SplitEx("a = b = c = ", " = ", true)
arr4 := strutil.SplitEx(" a = b = c = ", " = ", false) fmt.Println(result1)
fmt.Println(arr4) //[]string{" a", "b", "c", ""} fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
arr5 := strutil.SplitEx(" a = b = c = ", " = ", true) // Output:
fmt.Println(arr5) //[]string{" a", "b", "c"} // []
// [ a b c ]
// [a b c]
// [a b c ]
} }
``` ```
### <span id="Substring">Substring</span>
<p>Returns a substring of the specified length starting at the specified offset position.</p>
<b>Signature:</b>
```go
func Substring(s string, offset int, length uint) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.Substring("abcde", 1, 3)
result2 := strutil.Substring("abcde", 1, 5)
result3 := strutil.Substring("abcde", -1, 3)
result4 := strutil.Substring("abcde", -2, 2)
result5 := strutil.Substring("abcde", -2, 3)
result6 := strutil.Substring("你好,欢迎你", 0, 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// bcd
// bcde
// e
// de
// de
// 你好
}
```
### <span id="Wrap">Wrap</span> ### <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>
@@ -547,28 +707,27 @@ import (
) )
func main() { func main() {
s1 := strutil.Wrap("ab", "") result1 := strutil.Wrap("foo", "")
fmt.Println(s1) //ab result2 := strutil.Wrap("foo", "*")
result3 := strutil.Wrap("'foo'", "'")
result4 := strutil.Wrap("", "*")
s2 := strutil.Wrap("", "*") fmt.Println(result1)
fmt.Println(s2) //"" fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
s3 := strutil.Wrap("ab", "*") // Output:
fmt.Println(s3) //*ab* // foo
// *foo*
s4 := strutil.Wrap("ab", "\"") // ''foo''
fmt.Println(s4) //\"ab\" //
s5 := strutil.Wrap("ab", "'")
fmt.Println(s5) //'ab'
} }
``` ```
### <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>
@@ -584,20 +743,24 @@ import (
) )
func main() { func main() {
s1 := strutil.Unwrap("ab", "") result1 := strutil.Unwrap("foo", "")
fmt.Println(s1) //ab result2 := strutil.Unwrap("*foo*", "*")
result3 := strutil.Unwrap("*foo", "*")
result4 := strutil.Unwrap("foo*", "*")
result5 := strutil.Unwrap("**foo**", "*")
s2 := strutil.Unwrap("ab", "*") fmt.Println(result1)
fmt.Println(s2) //ab fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
s3 := strutil.Unwrap("**ab**", "*") // Output:
fmt.Println(s3) //*ab* // foo
// foo
s4 := strutil.Unwrap("*ab", "*") // *foo
fmt.Println(s4) //*ab // foo*
// *foo*
s5 := strutil.Unwrap("***", "**")
fmt.Println(s5) //***
} }
``` ```
+412 -256
View File
@@ -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,14 +49,14 @@ import (
### <span id="After">After</span> ### <span id="After">After</span>
<p>截取源字符串中char首次出现时的位置之后的子字符串</p> <p>返回源字符串中特定字符串首次出现时的位置之后的子字符串</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func After(s, char string) string func After(s, char string) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -62,28 +65,36 @@ import (
) )
func main() { func main() {
s1 := strutil.After("lancet", "") result1 := strutil.After("foo", "")
fmt.Println(s1) //lancet result2 := strutil.After("foo", "foo")
result3 := strutil.After("foo/bar", "foo")
result4 := strutil.After("foo/bar", "/")
result5 := strutil.After("foo/bar/baz", "/")
s2 := strutil.After("github.com/test/lancet", "/") fmt.Println(result1)
fmt.Println(s2) //test/lancet fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
s3 := strutil.After("github.com/test/lancet", "test") // Output:
fmt.Println(s3) // /lancet // foo
//
// /bar
// bar
// bar/baz
} }
``` ```
### <span id="AfterLast">AfterLast</span> ### <span id="AfterLast">AfterLast</span>
<p>截取源字符串中char最后一次出现时的位置之后的子字符串</p> <p>返回源字符串中指定字符串最后一次出现时的位置之后的子字符串</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func AfterLast(s, char string) string func AfterLast(s, char string) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -92,29 +103,36 @@ import (
) )
func main() { func main() {
s1 := strutil.AfterLast("lancet", "") result1 := strutil.AfterLast("foo", "")
fmt.Println(s1) //lancet result2 := strutil.AfterLast("foo", "foo")
result3 := strutil.AfterLast("foo/bar", "/")
result4 := strutil.AfterLast("foo/bar/baz", "/")
result5 := strutil.AfterLast("foo/bar/foo/baz", "foo")
s2 := strutil.AfterLast("github.com/test/lancet", "/") fmt.Println(result1)
fmt.Println(s2) //lancet fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
s3 := strutil.AfterLast("github.com/test/test/lancet", "test") // Output:
fmt.Println(s3) // /lancet // foo
//
// bar
// baz
// /baz
} }
``` ```
### <span id="Before">Before</span> ### <span id="Before">Before</span>
<p>截取源字符串中char首次出现时的位置之前的子字符串</p> <p>返回源字符串中指定字符串第一次出现时的位置之前的子字符串</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func Before(s, char string) string func Before(s, char string) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -123,29 +141,33 @@ import (
) )
func main() { func main() {
s1 := strutil.Before("lancet", "") result1 := strutil.Before("foo", "")
fmt.Println(s1) //lancet result2 := strutil.Before("foo", "foo")
result3 := strutil.Before("foo/bar", "/")
result4 := strutil.Before("foo/bar/baz", "/")
s2 := strutil.Before("github.com/test/lancet", "/") fmt.Println(result1)
fmt.Println(s2) //github.com fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
s3 := strutil.Before("github.com/test/lancet", "test") // Output:
fmt.Println(s3) // github.com/ // foo
//
// foo
// foo
} }
``` ```
### <span id="BeforeLast">BeforeLast</span> ### <span id="BeforeLast">BeforeLast</span>
<p>截取源字符串中char最后一次出现时的位置之前的子字符串</p> <p>返回源字符串中指定字符串最后一次出现时的位置之前的子字符串</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func BeforeLast(s, char string) string func BeforeLast(s, char string) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -154,29 +176,33 @@ import (
) )
func main() { func main() {
s1 := strutil.BeforeLast("lancet", "") result1 := strutil.BeforeLast("foo", "")
fmt.Println(s1) //lancet result2 := strutil.BeforeLast("foo", "foo")
result3 := strutil.BeforeLast("foo/bar", "/")
result4 := strutil.BeforeLast("foo/bar/baz", "/")
s2 := strutil.BeforeLast("github.com/test/lancet", "/") fmt.Println(result1)
fmt.Println(s2) //github.com/test fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
s3 := strutil.BeforeLast("github.com/test/test/lancet", "test") // Output:
fmt.Println(s3) //github.com/test/ // foo
//
// foo
// foo/bar
} }
``` ```
### <span id="CamelCase">CamelCase</span> ### <span id="CamelCase">CamelCase</span>
<p>将字符串转换为驼峰式字符串</p> <p>将字符串转换为驼峰式字符串, 非字母和数字会被忽略。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func CamelCase(s string) string func CamelCase(s string) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -185,90 +211,31 @@ import (
) )
func main() { func main() {
s1 := strutil.CamelCase("foo_bar") strings := []string{"", "foobar", "&FOO:BAR$BAZ", "$foo%", "Foo-#1😄$_%^&*(1bar"}
fmt.Println(s1) //fooBar
s2 := strutil.CamelCase("Foo-Bar") for _, v := range strings {
fmt.Println(s2) //fooBar s := strutil.CamelCase(v)
fmt.Println(s)
}
s3 := strutil.CamelCase("Foo&bar") // Output:
fmt.Println(s3) //fooBar //
// foobar
s4 := strutil.CamelCase("foo bar") // fooBarBaz
fmt.Println(s4) //fooBar // foo
// foo11Bar
} }
``` ```
### <span id="Capitalize">Capitalize</span>
<p>将字符串的第一个字符转换为大写</p>
<b>函数签名:</b>
```go
func Capitalize(s string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.Capitalize("foo")
fmt.Println(s1) //foo
s2 := strutil.Capitalize("Foo")
fmt.Println(s2) //foo
s3 := strutil.Capitalize("FOo"
fmt.Println(s3) //fOo
}
```
### <span id="IsString">IsString</span>
<p>检查值的数据类型是否为字符串</p>
<b>函数签名:</b>
```go
func IsString(v any) bool
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
fmt.Println(strutil.IsString("lancet")) //true
fmt.Println(strutil.IsString("")) //true
fmt.Println(strutil.IsString(1)) //false
fmt.Println(strutil.IsString("")) //false
fmt.Println(strutil.IsString([]string{})) //false
}
```
### <span id="KebabCase">KebabCase</span> ### <span id="KebabCase">KebabCase</span>
<p>将字符串转换为kebab-case</p> <p>将字符串转换为kebab-case, 非字母和数字会被忽略。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func KebabCase(s string) string func KebabCase(s string) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -277,32 +244,135 @@ import (
) )
func main() { func main() {
s1 := strutil.KebabCase("Foo Bar-") strings := []string{"", "foo-bar", "Foo Bar-", "FOOBAR", "Foo-#1😄$_%^&*(1bar"}
fmt.Println(s1) //foo-bar
s2 := strutil.KebabCase("foo_Bar") for _, v := range strings {
fmt.Println(s2) //foo-bar s := strutil.KebabCase(v)
fmt.Println(s)
}
s3 := strutil.KebabCase("fooBar") // Output:
fmt.Println(s3) //foo-bar //
// foo-bar
s4 := strutil.KebabCase("__FOO_BAR__") // foo-bar
fmt.Println(s4) //f-o-o-b-a-r // foobar
// foo-1-1-bar
} }
``` ```
### <span id="UpperKebabCase">UpperKebabCase</span>
<p>将字符串转换为大写KEBAB-CASE, 非字母和数字会被忽略。</p>
<b>函数签名:</b>
```go
func UpperKebabCase(s string) string
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
strings := []string{"", "foo-bar", "Foo Bar-", "FooBAR", "Foo-#1😄$_%^&*(1bar"}
for _, v := range strings {
s := strutil.UpperKebabCase(v)
fmt.Println(s)
}
// Output:
//
// FOO-BAR
// FOO-BAR
// FOO-BAR
// FOO-1-1-BAR
}
```
### <span id="Capitalize">Capitalize</span>
<p>将字符串的第一个字符转换为大写。</p>
<b>函数签名:</b>
```go
func Capitalize(s string) string
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
strings := []string{"", "Foo", "_foo", "fooBar", "foo-bar"}
for _, v := range strings {
s := strutil.Capitalize(v)
fmt.Println(s)
}
// Output:
//
// Foo
// _foo
// Foobar
// Foo-bar
}
```
### <span id="IsString">IsString</span>
<p>判断传入参数的数据类型是否为字符串。</p>
<b>函数签名:</b>
```go
func IsString(v any) bool
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.IsString("")
result2 := strutil.IsString("a")
result3 := strutil.IsString(1)
result4 := strutil.IsString(true)
result5 := strutil.IsString([]string{"a"})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// true
// true
// false
// false
// false
}
```
### <span id="LowerFirst">LowerFirst</span> ### <span id="LowerFirst">LowerFirst</span>
<p>将字符串的第一个字符转换为小写</p> <p>将字符串的第一个字符转换为小写</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func LowerFirst(s string) string func LowerFirst(s string) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -311,32 +381,30 @@ import (
) )
func main() { func main() {
s1 := strutil.LowerFirst("foo") strings := []string{"", "bar", "BAr", "Bar大"}
fmt.Println(s1) //foo
s2 := strutil.LowerFirst("BAR") for _, v := range strings {
fmt.Println(s2) //bAR s := strutil.LowerFirst(v)
fmt.Println(s)
}
s3 := strutil.LowerFirst("FOo") // Output:
fmt.Println(s3) //fOo //
// bar
s4 := strutil.LowerFirst("fOo大") // bAr
fmt.Println(s4) //fOo // bar
} }
``` ```
### <span id="UpperFirst">UpperFirst</span> ### <span id="UpperFirst">UpperFirst</span>
<p>将字符串的第一个字符转换为大写</p> <p>将字符串的第一个字符转换为大写形式。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func UpperFirst(s string) string func UpperFirst(s string) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -345,32 +413,30 @@ import (
) )
func main() { func main() {
s1 := strutil.UpperFirst("foo") strings := []string{"", "bar", "BAr", "bar大"}
fmt.Println(s1) //Foo
s2 := strutil.UpperFirst("bAR") for _, v := range strings {
fmt.Println(s2) //BAR s := strutil.UpperFirst(v)
fmt.Println(s)
}
s3 := strutil.UpperFirst("FOo") // Output:
fmt.Println(s3) //FOo //
// Bar
s4 := strutil.UpperFirst("fOo大") // BAr
fmt.Println(s4) //FOo // Bar
} }
``` ```
### <span id="PadEnd">PadEnd</span> ### <span id="PadEnd">PadEnd</span>
<p>如果字符串长度短于size,则在右侧填充字符串</p> <p>如果字符串长度短于size,则在右侧填充字符串</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func PadEnd(source string, size int, padStr string) string func PadEnd(source string, size int, padStr string) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -379,32 +445,42 @@ import (
) )
func main() { func main() {
s1 := strutil.PadEnd("a", 1, "b") result1 := strutil.PadEnd("foo", 1, "bar")
fmt.Println(s1) //a result2 := strutil.PadEnd("foo", 2, "bar")
result3 := strutil.PadEnd("foo", 3, "bar")
result4 := strutil.PadEnd("foo", 4, "bar")
result5 := strutil.PadEnd("foo", 5, "bar")
result6 := strutil.PadEnd("foo", 6, "bar")
result7 := strutil.PadEnd("foo", 7, "bar")
s2 := strutil.PadEnd("a", 2, "b") fmt.Println(result1)
fmt.Println(s2) //ab fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
s3 := strutil.PadEnd("abcd", 6, "mno") // Output:
fmt.Println(s3) //abcdmn // foo
// foo
s4 := strutil.PadEnd("abc", 6, "ab") // foo
fmt.Println(s4) //abcaba // foob
// fooba
// foobar
// foobarb
} }
``` ```
### <span id="PadStart">PadStart</span> ### <span id="PadStart">PadStart</span>
<p>如果字符串长度短于size,则在左侧填充字符串</p> <p>如果字符串长度短于size,则在左侧填充字符串</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func PadStart(source string, size int, padStr string) string func PadStart(source string, size int, padStr string) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -413,32 +489,42 @@ import (
) )
func main() { func main() {
s1 := strutil.PadStart("a", 1, "b") result1 := strutil.PadStart("foo", 1, "bar")
fmt.Println(s1) //a result2 := strutil.PadStart("foo", 2, "bar")
result3 := strutil.PadStart("foo", 3, "bar")
result4 := strutil.PadStart("foo", 4, "bar")
result5 := strutil.PadStart("foo", 5, "bar")
result6 := strutil.PadStart("foo", 6, "bar")
result7 := strutil.PadStart("foo", 7, "bar")
s2 := strutil.PadStart("a", 2, "b") fmt.Println(result1)
fmt.Println(s2) //ba fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
fmt.Println(result7)
s3 := strutil.PadStart("abcd", 6, "mno") // Output:
fmt.Println(s3) //mnabcd // foo
// foo
s4 := strutil.PadStart("abc", 6, "ab") // foo
fmt.Println(s4) //abaabc // bfoo
// bafoo
// barfoo
// barbfoo
} }
``` ```
### <span id="Reverse">Reverse</span> ### <span id="Reverse">Reverse</span>
<p>返回字符顺序与给定字符串相反的字符串</p> <p>返回字符顺序与给定字符串相反的字符串</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func Reverse(s string) string func Reverse(s string) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -447,25 +533,27 @@ import (
) )
func main() { func main() {
s1 := strutil.ReverseStr("abc") s := "foo"
fmt.Println(s1) //cba rs := strutil.Reverse(s)
s2 := strutil.ReverseStr("12345") fmt.Println(s)
fmt.Println(s2) //54321 fmt.Println(rs)
// Output:
// foo
// oof
} }
``` ```
### <span id="SnakeCase">SnakeCase</span> ### <span id="SnakeCase">SnakeCase</span>
<p>将字符串转换为snake_case形式</p> <p>将字符串转换为snake_case形式, 非字母和数字会被忽略。</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func SnakeCase(s string) string func SnakeCase(s string) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -474,34 +562,64 @@ import (
) )
func main() { func main() {
s1 := strutil.SnakeCase("Foo Bar-") strings := []string{"", "foo-bar", "Foo Bar-", "FOOBAR", "Foo-#1😄$_%^&*(1bar"}
fmt.Println(s1) //foo_bar
s2 := strutil.SnakeCase("foo_Bar") for _, v := range strings {
fmt.Println(s2) //foo_bar s := strutil.SnakeCase(v)
fmt.Println(s)
}
s3 := strutil.SnakeCase("fooBar") // Output:
fmt.Println(s3) //foo_bar //
// foo_bar
s4 := strutil.SnakeCase("__FOO_BAR__") // foo_bar
fmt.Println(s4) //f_o_o_b_a_r // foobar
// foo_1_1_bar
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
fmt.Println(s5) //a_bbc_s_a_b_b_c
} }
``` ```
### <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() {
strings := []string{"", "foo-bar", "Foo Bar-", "FooBAR", "Foo-#1😄$_%^&*(1bar"}
for _, v := range strings {
s := strutil.UpperSnakeCase(v)
fmt.Println(s)
}
// Output:
//
// FOO_BAR
// FOO_BAR
// FOO_BAR
// FOO_1_1_BAR
}
```
### <span id="SplitEx">SplitEx</span> ### <span id="SplitEx">SplitEx</span>
<p>分割字符串为切片,removeEmptyString参数指定是否去除空字符串</p> <p>分割字符串为切片,removeEmptyString参数指定是否去除空字符串</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func SplitEx(s, sep string, removeEmptyString bool) []string func SplitEx(s, sep string, removeEmptyString bool) []string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -510,34 +628,78 @@ import (
) )
func main() { func main() {
arr1 := strutil.SplitEx(" a b c ", "", true) result1 := strutil.SplitEx(" a b c ", "", true)
fmt.Println(arr1) //[]string{}
arr2 := strutil.SplitEx(" a b c ", " ", false) result2 := strutil.SplitEx(" a b c ", " ", false)
fmt.Println(arr2) //[]string{"", "a", "b", "c", ""} result3 := strutil.SplitEx(" a b c ", " ", true)
arr3 := strutil.SplitEx(" a b c ", " ", true) result4 := strutil.SplitEx("a = b = c = ", " = ", false)
fmt.Println(arr3) //[]string{"a", "b", "c"} result5 := strutil.SplitEx("a = b = c = ", " = ", true)
arr4 := strutil.SplitEx(" a = b = c = ", " = ", false) fmt.Println(result1)
fmt.Println(arr4) //[]string{" a", "b", "c", ""} fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
arr5 := strutil.SplitEx(" a = b = c = ", " = ", true) // Output:
fmt.Println(arr5) //[]string{" a", "b", "c"} // []
// [ a b c ]
// [a b c]
// [a b c ]
} }
``` ```
### <span id="Substring">Substring</span>
<p>根据指定的位置和长度截取字符串。</p>
<b>函数签名:</b>
```go
func Substring(s string, offset int, length uint) string
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.Substring("abcde", 1, 3)
result2 := strutil.Substring("abcde", 1, 5)
result3 := strutil.Substring("abcde", -1, 3)
result4 := strutil.Substring("abcde", -2, 2)
result5 := strutil.Substring("abcde", -2, 3)
result6 := strutil.Substring("你好,欢迎你", 0, 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
fmt.Println(result6)
// Output:
// bcd
// bcde
// e
// de
// de
// 你好
}
```
### <span id="Wrap">Wrap</span> ### <span id="Wrap">Wrap</span>
<p>用另一个字符串包裹一个字符串</p> <p>用另一个字符串包裹一个字符串</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func Wrap(str string, wrapWith string) string func Wrap(str string, wrapWith string) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -546,35 +708,34 @@ import (
) )
func main() { func main() {
s1 := strutil.Wrap("ab", "") result1 := strutil.Wrap("foo", "")
fmt.Println(s1) //ab result2 := strutil.Wrap("foo", "*")
result3 := strutil.Wrap("'foo'", "'")
result4 := strutil.Wrap("", "*")
s2 := strutil.Wrap("", "*") fmt.Println(result1)
fmt.Println(s2) //"" fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
s3 := strutil.Wrap("ab", "*") // Output:
fmt.Println(s3) //*ab* // foo
// *foo*
s4 := strutil.Wrap("ab", "\"") // ''foo''
fmt.Println(s4) //\"ab\" //
s5 := strutil.Wrap("ab", "'")
fmt.Println(s5) //'ab'
} }
``` ```
### <span id="Wrap">Wrap</span>
<p>用另一个字符串解开包裹一个字符串。</p>
### <span id="Unwrap">Unwrap</span>
<p>用另一个字符串解开包裹一个字符串</p>
<b>函数签名:</b> <b>函数签名:</b>
```go ```go
func Unwrap(str string, wrapToken string) string func Unwrap(str string, wrapToken string) string
``` ```
<b>例:</b> <b>例:</b>
```go ```go
import ( import (
@@ -583,28 +744,23 @@ import (
) )
func main() { func main() {
s1 := strutil.Unwrap("ab", "") result1 := strutil.Unwrap("foo", "")
fmt.Println(s1) //ab result2 := strutil.Unwrap("*foo*", "*")
result3 := strutil.Unwrap("*foo", "*")
result4 := strutil.Unwrap("foo*", "*")
result5 := strutil.Unwrap("**foo**", "*")
s2 := strutil.Unwrap("ab", "*") fmt.Println(result1)
fmt.Println(s2) //ab fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
s3 := strutil.Unwrap("**ab**", "*") // Output:
fmt.Println(s3) //*ab* // foo
// foo
s4 := strutil.Unwrap("*ab", "*") // *foo
fmt.Println(s4) //*ab // foo*
// *foo*
s5 := strutil.Unwrap("***", "**")
fmt.Println(s5) //***
} }
``` ```
+20 -6
View File
@@ -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())
}
} }
``` ```
+20 -7
View File
@@ -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-alinux),dirwindows),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())
}
} }
``` ```
+29 -1
View File
@@ -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")
}
```
+29 -6
View File
@@ -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")
}
```
+9 -1
View File
@@ -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
} }
``` ```
+10 -2
View File
@@ -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
} }
``` ```
+47 -22
View File
@@ -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
View 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
}
+34 -17
View File
@@ -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)
}
+58 -4
View File
@@ -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
View 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
}
-40
View File
@@ -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 ""
}
+5 -1
View File
@@ -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, ""))
} }
+48 -22
View File
@@ -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: https://go.dev/play/p/5HopfDwANKX
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: https://go.dev/play/p/KKfugD4PKYF
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
View File
@@ -0,0 +1,147 @@
package function
import (
"fmt"
"strings"
"time"
)
func ExampleAfter() {
fn := After(2, func() {
fmt.Println("test")
})
fn()
fn()
// Output:
// test
}
func ExampleBefore() {
fn := Before(2, func() {
fmt.Println("test")
})
fn()
fn()
fn()
fn()
// Output:
// test
// test
}
func ExampleCurryFn_New() {
add := func(a, b int) int {
return a + b
}
var addCurry CurryFn[int] = func(values ...int) int {
return add(values[0], values[1])
}
add1 := addCurry.New(1)
result := add1(2)
fmt.Println(result)
// Output:
// 3
}
func ExampleCompose() {
toUpper := func(strs ...string) string {
return strings.ToUpper(strs[0])
}
toLower := func(strs ...string) string {
return strings.ToLower(strs[0])
}
transform := Compose(toUpper, toLower)
result := transform("aBCde")
fmt.Println(result)
// Output:
// ABCDE
}
func ExampleDelay() {
var print = func(s string) {
fmt.Println(s)
}
Delay(2*time.Second, print, "hello")
// Output:
// hello
}
func ExampleDebounced() {
count := 0
add := func() {
count++
}
debouncedAdd := Debounced(add, 50*time.Microsecond)
debouncedAdd()
debouncedAdd()
debouncedAdd()
debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count)
debouncedAdd()
time.Sleep(100 * time.Millisecond)
fmt.Println(count)
// Output:
// 1
// 2
}
func ExampleSchedule() {
count := 0
increase := func() {
count++
}
stop := Schedule(2*time.Second, increase)
time.Sleep(2 * time.Second)
close(stop)
fmt.Println(count)
// Output:
// 2
}
func ExamplePipeline() {
addOne := func(x int) int {
return x + 1
}
double := func(x int) int {
return 2 * x
}
square := func(x int) int {
return x * x
}
fn := Pipeline(addOne, double, square)
result := fn(2)
fmt.Println(result)
// Output:
// 36
}
-39
View File
@@ -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))
}
}
+9 -7
View File
@@ -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")
+6
View File
@@ -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: https://go.dev/play/p/l2yrOpCLd1I
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
View 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
}
+1 -1
View File
@@ -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
View File
@@ -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
View 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=
+50 -17
View File
@@ -3,14 +3,18 @@
// Package iterator provides a way to iterate over values stored in containers. // Package iterator provides a way to iterate over values stored in containers.
// note: // note:
// 1. Full feature iterator is complicated, this pacakge is just a experiment to explore how iterators could work in Go. // 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. // 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. // 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. // 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 // 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
}
+53
View File
@@ -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)
} }
+79 -1
View File
@@ -3,7 +3,7 @@
// Package iterator provides a way to iterate over values stored in containers. // Package iterator provides a way to iterate over values stored in containers.
// note: // note:
// 1. Full feature iterator is complicated, this pacakge is just a experiment to explore how iterators could work in Go. // 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. // 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. // 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. // So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
@@ -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
View 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)
}
-10
View File
@@ -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