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

Compare commits

..

83 Commits

Author SHA1 Message Date
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
120 changed files with 8633 additions and 2498 deletions
+751 -258
View File
File diff suppressed because it is too large Load Diff
+762 -263
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
}
// NewLRUCache return a LRUCache pointer
// NewLRUCache creates a LRUCache pointer instance.
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
return &LRUCache[K, V]{
cache: make(map[K]*lruNode[K, V], capacity),
@@ -37,7 +37,8 @@ func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V] {
}
}
// Get value of key from lru cache
// Get value of key from lru cache.
// Play: https://go.dev/play/p/iUynEfOP8G0
func (l *LRUCache[K, V]) Get(key K) (V, bool) {
var value V
@@ -50,7 +51,8 @@ func (l *LRUCache[K, V]) Get(key K) (V, bool) {
return value, false
}
// Put value of key into lru cache
// Put value of key into lru cache.
// Play: https://go.dev/play/p/iUynEfOP8G0
func (l *LRUCache[K, V]) Put(key K, value V) {
node, ok := l.cache[key]
if !ok {
@@ -69,6 +71,23 @@ func (l *LRUCache[K, V]) Put(key K, value V) {
l.length = len(l.cache)
}
// Delete item from lru cache.
func (l *LRUCache[K, V]) Delete(key K) bool {
node, ok := l.cache[key]
if ok {
key := l.deleteNode(node)
delete(l.cache, key)
return true
}
return false
}
// Len returns the number of items in the cache.
func (l *LRUCache[K, V]) Len() int {
return l.length
}
func (l *LRUCache[K, V]) addNode(node *lruNode[K, V]) {
if l.tail != nil {
l.tail.next = node
+79
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) {
asssert := internal.NewAssert(t, "TestLRUCache")
cache := NewLRUCache[int, int](2)
cache := NewLRUCache[int, int](3)
cache.Put(1, 1)
cache.Put(2, 2)
cache.Put(3, 3)
_, ok := cache.Get(0)
asssert.Equal(false, ok)
asssert.Equal(3, cache.Len())
v, ok := cache.Get(1)
asssert.Equal(true, ok)
@@ -25,12 +25,9 @@ func TestLRUCache(t *testing.T) {
asssert.Equal(true, ok)
asssert.Equal(2, v)
cache.Put(3, 3)
v, ok = cache.Get(1)
asssert.Equal(false, ok)
asssert.NotEqual(1, v)
v, ok = cache.Get(3)
ok = cache.Delete(2)
asssert.Equal(true, ok)
asssert.Equal(3, v)
_, ok = cache.Get(2)
asssert.Equal(false, ok)
}
+12 -9
View File
@@ -1,26 +1,28 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package algorithm contain some basic algorithm functions. eg. sort, search, list, linklist, stack, queue, tree, graph. TODO
// Package algorithm contain some basic algorithm functions. eg. sort, search, list, linklist, stack, queue, tree, graph.
package algorithm
import "github.com/duke-git/lancet/v2/lancetconstraints"
// Search algorithms see https://github.com/TheAlgorithms/Go/tree/master/search
// LinearSearch Simple linear search algorithm that iterates over all elements of an slice
// If a target is found, the index of the target is returned. Else the function return -1
func LinearSearch[T any](slice []T, target T, comparator lancetconstraints.Comparator) int {
// LinearSearch return the index of target in slice base on equal function.
// If not found return -1
// Play: Todo
func LinearSearch[T any](slice []T, target T, equal func(a, b T) bool) int {
for i, v := range slice {
if comparator.Compare(v, target) == 0 {
if equal(v, target) {
return i
}
}
return -1
}
// BinarySearch search for target within a sorted slice, recursive call itself.
// If a target is found, the index of the target is returned. Else the function return -1
// BinarySearch return the index of target within a sorted slice, use binary search (recursive call itself).
// If not found return -1.
// Play: https://go.dev/play/p/t6MeGiUSN47
func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
if highIndex < lowIndex || len(sortedSlice) == 0 {
return -1
@@ -39,8 +41,9 @@ func BinarySearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, com
return midIndex
}
// BinaryIterativeSearch search for target within a sorted slice.
// If a target is found, the index of the target is returned. Else the function return -1
// BinaryIterativeSearch return the index of target within a sorted slice, use binary search (no recursive).
// If not found return -1.
// Play: https://go.dev/play/p/Anozfr8ZLH3
func BinaryIterativeSearch[T any](sortedSlice []T, target T, lowIndex, highIndex int, comparator lancetconstraints.Comparator) int {
startIndex := lowIndex
endIndex := highIndex
+51
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"
)
var sortedNumbers = []int{1, 2, 3, 4, 5, 6, 7, 8}
func TestLinearSearch(t *testing.T) {
asssert := internal.NewAssert(t, "TestLinearSearch")
comparator := &intComparator{}
asssert.Equal(4, LinearSearch(sortedNumbers, 5, comparator))
asssert.Equal(-1, LinearSearch(sortedNumbers, 9, comparator))
numbers := []int{3, 4, 5, 3, 2, 1}
equalFunc := func(a, b int) bool {
return a == b
}
asssert.Equal(0, LinearSearch(numbers, 3, equalFunc))
asssert.Equal(-1, LinearSearch(numbers, 6, equalFunc))
}
func TestBinarySearch(t *testing.T) {
asssert := internal.NewAssert(t, "TestBinarySearch")
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
asssert.Equal(4, BinarySearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
asssert.Equal(-1, BinarySearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
}
@@ -27,7 +31,9 @@ func TestBinarySearch(t *testing.T) {
func TestBinaryIterativeSearch(t *testing.T) {
asssert := internal.NewAssert(t, "TestBinaryIterativeSearch")
sortedNumbers := []int{1, 2, 3, 4, 5, 6, 7, 8}
comparator := &intComparator{}
asssert.Equal(4, BinaryIterativeSearch(sortedNumbers, 5, 0, len(sortedNumbers)-1, comparator))
asssert.Equal(-1, BinaryIterativeSearch(sortedNumbers, 9, 0, len(sortedNumbers)-1, comparator))
}
+16 -9
View File
@@ -1,12 +1,12 @@
// Copyright 2021 dudaodong@gmail.com. All rights reserved.
// Use of this source code is governed by MIT license
// Package algorithm contain some basic algorithm functions. eg. sort, search
package algorithm
import "github.com/duke-git/lancet/v2/lancetconstraints"
// BubbleSort use bubble to sort slice.
// BubbleSort applys the bubble sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/GNdv7Jg2Taj
func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
for i := 0; i < len(slice); i++ {
for j := 0; j < len(slice)-1-i; j++ {
@@ -18,7 +18,8 @@ func BubbleSort[T any](slice []T, comparator lancetconstraints.Comparator) {
}
}
// InsertionSort use insertion to sort slice.
// InsertionSort applys the insertion sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/G5LJiWgJJW6
func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
for i := 0; i < len(slice); i++ {
for j := i; j > 0; j-- {
@@ -32,7 +33,8 @@ func InsertionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
}
}
// SelectionSort use selection to sort slice.
// SelectionSort applys the selection sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/oXovbkekayS
func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
for i := 0; i < len(slice); i++ {
min := i
@@ -45,7 +47,8 @@ func SelectionSort[T any](slice []T, comparator lancetconstraints.Comparator) {
}
}
// ShellSort shell sort slice.
// ShellSort applys the shell sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/3ibkszpJEu3
func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
size := len(slice)
@@ -64,7 +67,8 @@ func ShellSort[T any](slice []T, comparator lancetconstraints.Comparator) {
}
}
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1
// QuickSort quick sorting for slice, lowIndex is 0 and highIndex is len(slice)-1.
// Play: https://go.dev/play/p/7Y7c1Elk3ax
func QuickSort[T any](slice []T, comparator lancetconstraints.Comparator) {
quickSort(slice, 0, len(slice)-1, comparator)
}
@@ -93,7 +97,8 @@ func partition[T any](slice []T, lowIndex, highIndex int, comparator lancetconst
return i
}
// HeapSort use heap to sort slice
// HeapSort applys the heap sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/u6Iwa1VZS_f
func HeapSort[T any](slice []T, comparator lancetconstraints.Comparator) {
size := len(slice)
@@ -126,7 +131,8 @@ func sift[T any](slice []T, lowIndex, highIndex int, comparator lancetconstraint
slice[i] = temp
}
// MergeSort merge sorting for slice
// MergeSort applys the merge sort algorithm to sort the collection, will change the original collection data.
// Play: https://go.dev/play/p/ydinn9YzUJn
func MergeSort[T any](slice []T, comparator lancetconstraints.Comparator) {
mergeSort(slice, 0, len(slice)-1, comparator)
}
@@ -167,7 +173,8 @@ func merge[T any](slice []T, lowIndex, midIndex, highIndex int, comparator lance
}
}
// CountSort use count sorting for slice
// CountSort applys the count sort algorithm to sort the collection, don't change the original collection data.
// Play: https://go.dev/play/p/tB-Umgm0DrP
func CountSort[T any](slice []T, comparator lancetconstraints.Comparator) []T {
size := len(slice)
out := make([]T, size)
+93
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) {
asssert := internal.NewAssert(t, "TestBubbleSortForIntSlice")
numbers := []int{2, 1, 5, 3, 6, 4}
comparator := &intComparator{}
BubbleSort(numbers, comparator)
+47 -43
View File
@@ -11,17 +11,18 @@ import (
// Channel is a logic object which can generate or manipulate go channel
// all methods of Channel are in the book tilted《Concurrency in Go》
type Channel struct {
type Channel[T any] struct {
}
// NewChannel return a Channel instance
func NewChannel() *Channel {
return &Channel{}
func NewChannel[T any]() *Channel[T] {
return &Channel[T]{}
}
// Generate a data of type any chan, put param `values` into the chan
func (c *Channel) Generate(ctx context.Context, values ...any) <-chan any {
dataStream := make(chan any)
// Generate creates channel, then put values into the channel.
// Play: Todo
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T {
dataStream := make(chan T)
go func() {
defer close(dataStream)
@@ -38,9 +39,10 @@ func (c *Channel) Generate(ctx context.Context, values ...any) <-chan any {
return dataStream
}
// Repeat return a data of type any chan, put param `values` into the chan repeatly until cancel the context.
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any {
dataStream := make(chan any)
// Repeat create channel, put values into the channel repeatly until cancel the context.
// Play: Todo
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T {
dataStream := make(chan T)
go func() {
defer close(dataStream)
@@ -57,10 +59,11 @@ func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any {
return dataStream
}
// RepeatFn return a chan, excutes fn repeatly, and put the result into retruned chan
// until close the `done` channel
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any {
dataStream := make(chan any)
// RepeatFn create a channel, excutes fn repeatly, and put the result into the channel
// until close context.
// Play: Todo
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T {
dataStream := make(chan T)
go func() {
defer close(dataStream)
@@ -75,9 +78,10 @@ func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any {
return dataStream
}
// Take return a chan whose values are tahken from another chan
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any {
takeStream := make(chan any)
// Take create a channel whose values are taken from another channel with limit number.
// Play: Todo
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T {
takeStream := make(chan T)
go func() {
defer close(takeStream)
@@ -94,16 +98,17 @@ func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int)
return takeStream
}
// FanIn merge multiple channels into one channel
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any {
out := make(chan any)
// FanIn merge multiple channels into one channel.
// Play: Todo
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T {
out := make(chan T)
go func() {
var wg sync.WaitGroup
wg.Add(len(channels))
for _, c := range channels {
go func(c <-chan any) {
go func(c <-chan T) {
defer wg.Done()
for v := range c {
select {
@@ -121,10 +126,11 @@ func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
return out
}
// Tee split one chanel into two channels
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any) {
out1 := make(chan any)
out2 := make(chan any)
// Tee split one chanel into two channels, until cancel the context.
// Play: Todo
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T) {
out1 := make(chan T)
out2 := make(chan T)
go func() {
defer close(out1)
@@ -147,18 +153,19 @@ func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan an
return out1, out2
}
// Bridge link multiply channels into one channel
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any {
valStream := make(chan any)
// Bridge link multiply channels into one channel.
// Play: Todo
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T {
valStream := make(chan T)
go func() {
defer close(valStream)
for {
var stream <-chan any
var stream <-chan T
select {
case maybeStream, ok := <-chanStream:
if ok == false {
if !ok {
return
}
stream = maybeStream
@@ -178,8 +185,9 @@ func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-ch
return valStream
}
// Or read one or more channels into one channel, will close when any readin channel is closed
func (c *Channel) Or(channels ...<-chan any) <-chan any {
// Or read one or more channels into one channel, will close when any readin channel is closed.
// Play: Todo
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T {
switch len(channels) {
case 0:
return nil
@@ -187,7 +195,7 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
return channels[0]
}
orDone := make(chan any)
orDone := make(chan T)
go func() {
defer close(orDone)
@@ -199,17 +207,12 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
case <-channels[1]:
}
default:
m := len(channels) / 2
select {
case <-c.Or(channels[:m]...):
case <-c.Or(channels[m:]...):
case <-channels[0]:
case <-channels[1]:
case <-channels[2]:
case <-c.Or(append(channels[3:], orDone)...):
}
// select {
// case <-channels[0]:
// case <-channels[1]:
// case <-channels[2]:
// case <-c.Or(append(channels[3:], orDone)...):
// }
}
}()
@@ -217,8 +220,9 @@ func (c *Channel) Or(channels ...<-chan any) <-chan any {
}
// OrDone read a channel into another channel, will close until cancel context.
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any {
valStream := make(chan any)
// Play: Todo
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T {
valStream := make(chan T)
go func() {
defer close(valStream)
+196
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())
defer cancel()
c := NewChannel()
c := NewChannel[int]()
intStream := c.Generate(ctx, 1, 2, 3)
// for v := range intStream {
// t.Log(v) //1, 2, 3
// }
assert.Equal(1, <-intStream)
assert.Equal(2, <-intStream)
assert.Equal(3, <-intStream)
@@ -31,12 +28,9 @@ func TestRepeat(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
c := NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
// for v := range intStream {
// t.Log(v) //1, 2, 1, 2, 1
// }
assert.Equal(1, <-intStream)
assert.Equal(2, <-intStream)
assert.Equal(1, <-intStream)
@@ -50,17 +44,13 @@ func TestRepeatFn(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() any {
fn := func() string {
s := "a"
return s
}
c := NewChannel()
c := NewChannel[string]()
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
// for v := range dataStream {
// t.Log(v) //a, a, a
// }
assert.Equal("a", <-dataStream)
assert.Equal("a", <-dataStream)
assert.Equal("a", <-dataStream)
@@ -72,7 +62,7 @@ func TestTake(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan any, 5)
numbers := make(chan int, 5)
numbers <- 1
numbers <- 2
numbers <- 3
@@ -80,7 +70,7 @@ func TestTake(t *testing.T) {
numbers <- 5
defer close(numbers)
c := NewChannel()
c := NewChannel[int]()
intStream := c.Take(ctx, numbers, 3)
assert.Equal(1, <-intStream)
@@ -94,8 +84,8 @@ func TestFanIn(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
channels := make([]<-chan any, 3)
c := NewChannel[int]()
channels := make([]<-chan int, 3)
for i := 0; i < 3; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
@@ -124,7 +114,7 @@ func TestOr(t *testing.T) {
start := time.Now()
c := NewChannel()
c := NewChannel[any]()
<-c.Or(
sig(1*time.Second),
sig(2*time.Second),
@@ -133,9 +123,7 @@ func TestOr(t *testing.T) {
sig(5*time.Second),
)
t.Logf("done after %v", time.Since(start))
assert.Equal(1, 1)
assert.Equal(true, time.Since(start).Seconds() < 2)
}
func TestOrDone(t *testing.T) {
@@ -144,16 +132,12 @@ func TestOrDone(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
c := NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
var res any
for val := range c.OrDone(ctx, intStream) {
t.Logf("%v", val)
res = val
assert.Equal(1, val)
}
assert.Equal(1, res)
}
func TestTee(t *testing.T) {
@@ -162,15 +146,13 @@ func TestTee(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
c := NewChannel[int]()
inStream := c.Take(ctx, c.Repeat(ctx, 1), 4)
out1, out2 := c.Tee(ctx, inStream)
for val := range out1 {
val1 := val
val2 := <-out2
// t.Log("val1 is", val1)
// t.Log("val2 is", val2)
assert.Equal(1, val1)
assert.Equal(1, val2)
}
@@ -182,13 +164,13 @@ func TestBridge(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := NewChannel()
genVals := func() <-chan <-chan any {
chanStream := make(chan (<-chan any))
c := NewChannel[int]()
genVals := func() <-chan <-chan int {
chanStream := make(chan (<-chan int))
go func() {
defer close(chanStream)
for i := 0; i < 10; i++ {
stream := make(chan any, 1)
stream := make(chan int, 1)
stream <- i
close(stream)
chanStream <- stream
+14 -6
View File
@@ -13,6 +13,7 @@ import "reflect"
// If the type has an IsZero() bool method, the opposite value is returned.
// Slices and maps are truthy if they have a length greater than zero.
// All other types are truthy if they are not their zero value.
// Play: https://go.dev/play/p/ETzeDJRSvhm
func Bool[T any](value T) bool {
switch m := any(value).(type) {
case interface{ Bool() bool }:
@@ -34,40 +35,47 @@ func reflectValue(vp any) bool {
}
// And returns true if both a and b are truthy.
// Play: https://go.dev/play/p/W1SSUmt6pvr
func And[T, U any](a T, b U) bool {
return Bool(a) && Bool(b)
}
// Or returns false iff neither a nor b is truthy.
// Or returns false if neither a nor b is truthy.
// Play: https://go.dev/play/p/UlQTxHaeEkq
func Or[T, U any](a T, b U) bool {
return Bool(a) || Bool(b)
}
// Xor returns true iff a or b but not both is truthy.
// Xor returns true if a or b but not both is truthy.
// Play: https://go.dev/play/p/gObZrW7ZbG8
func Xor[T, U any](a T, b U) bool {
valA := Bool(a)
valB := Bool(b)
return (valA || valB) && valA != valB
}
// Nor returns true iff neither a nor b is truthy.
// Nor returns true if neither a nor b is truthy.
// Play: https://go.dev/play/p/g2j08F_zZky
func Nor[T, U any](a T, b U) bool {
return !(Bool(a) || Bool(b))
}
// Xnor returns true iff both a and b or neither a nor b are truthy.
// Xnor returns true if both a and b or neither a nor b are truthy.
// Play: https://go.dev/play/p/OuDB9g51643
func Xnor[T, U any](a T, b U) bool {
valA := Bool(a)
valB := Bool(b)
return (valA && valB) || (!valA && !valB)
}
// Nand returns false iff both a and b are truthy.
// Nand returns false if both a and b are truthy.
// Play: https://go.dev/play/p/vSRMLxLIbq8
func Nand[T, U any](a T, b U) bool {
return !Bool(a) || !Bool(b)
}
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue
// TernaryOperator checks the value of param `isTrue`, if true return ifValue else return elseValue.
// Play: https://go.dev/play/p/ElllPZY0guT
func TernaryOperator[T, U any](isTrue T, ifValue U, elseValue U) U {
if Bool(isTrue) {
return ifValue
+163
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"
)
// ToBool convert string to a boolean
// ToBool convert string to boolean.
// Play: https://go.dev/play/p/ARht2WnGdIN
func ToBool(s string) (bool, error) {
return strconv.ParseBool(s)
}
// ToBytes convert interface to bytes
// ToBytes convert value to byte slice.
// Play: https://go.dev/play/p/fAMXYFDvOvr
func ToBytes(value any) ([]byte, error) {
v := reflect.ValueOf(value)
@@ -63,7 +65,8 @@ func ToBytes(value any) ([]byte, error) {
}
}
// ToChar convert string to char slice
// ToChar convert string to char slice.
// Play: https://go.dev/play/p/JJ1SvbFkVdM
func ToChar(s string) []string {
c := make([]string, 0)
if len(s) == 0 {
@@ -75,7 +78,8 @@ func ToChar(s string) []string {
return c
}
// ToChannel convert a array of elements to a read-only channels
// ToChannel convert a slice of elements to a read-only channel.
// Play: https://go.dev/play/p/hOx_oYZbAnL
func ToChannel[T any](array []T) <-chan T {
ch := make(chan T)
@@ -91,53 +95,58 @@ func ToChannel[T any](array []T) <-chan T {
// ToString convert value to string
// for number, string, []byte, will convert to string
// for other type (slice, map, array, struct) will call json.Marshal
// for other type (slice, map, array, struct) will call json.Marshal.
// Play: https://go.dev/play/p/nF1zOOslpQq
func ToString(value any) string {
if value == nil {
return ""
}
switch value.(type) {
switch val := value.(type) {
case float32:
return strconv.FormatFloat(float64(value.(float32)), 'f', -1, 32)
return strconv.FormatFloat(float64(val), 'f', -1, 32)
case float64:
return strconv.FormatFloat(value.(float64), 'f', -1, 64)
return strconv.FormatFloat(val, 'f', -1, 64)
case int:
return strconv.FormatInt(int64(value.(int)), 10)
return strconv.FormatInt(int64(val), 10)
case int8:
return strconv.FormatInt(int64(value.(int8)), 10)
return strconv.FormatInt(int64(val), 10)
case int16:
return strconv.FormatInt(int64(value.(int16)), 10)
return strconv.FormatInt(int64(val), 10)
case int32:
return strconv.FormatInt(int64(value.(int32)), 10)
return strconv.FormatInt(int64(val), 10)
case int64:
return strconv.FormatInt(value.(int64), 10)
return strconv.FormatInt(val, 10)
case uint:
return strconv.FormatUint(uint64(value.(uint)), 10)
return strconv.FormatUint(uint64(val), 10)
case uint8:
return strconv.FormatUint(uint64(value.(uint8)), 10)
return strconv.FormatUint(uint64(val), 10)
case uint16:
return strconv.FormatUint(uint64(value.(uint16)), 10)
return strconv.FormatUint(uint64(val), 10)
case uint32:
return strconv.FormatUint(uint64(value.(uint32)), 10)
return strconv.FormatUint(uint64(val), 10)
case uint64:
return strconv.FormatUint(value.(uint64), 10)
return strconv.FormatUint(val, 10)
case string:
return value.(string)
return val
case []byte:
return string(value.([]byte))
return string(val)
default:
newValue, _ := json.Marshal(value)
return string(newValue)
b, err := json.Marshal(val)
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)
// log.Panicf("Unsupported data type: %s ", v.String())
// 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) {
result, err := json.Marshal(value)
if err != nil {
@@ -147,7 +156,8 @@ func ToJson(value any) (string, error) {
return string(result), nil
}
// ToFloat convert value to a float64, if input is not a float return 0.0 and error
// ToFloat convert value to float64, if input is not a float return 0.0 and error.
// Play: https://go.dev/play/p/4YTmPCibqHJ
func ToFloat(value any) (float64, error) {
v := reflect.ValueOf(value)
@@ -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) {
v := reflect.ValueOf(value)
var result int64
err := fmt.Errorf("ToInt: invalid interface type %T", value)
err := fmt.Errorf("ToInt: invalid value type %T", value)
switch value.(type) {
case int, int8, int16, int32, int64:
result = v.Int()
@@ -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 {
return &value
}
// ToMap convert a slice or an array of structs to a map based on iteratee function
// ToMap convert a slice of structs to a map based on iteratee function.
// Play: https://go.dev/play/p/tVFy7E-t24l
func ToMap[T any, K comparable, V any](array []T, iteratee func(T) (K, V)) map[K]V {
result := make(map[K]V, len(array))
for _, item := range array {
@@ -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
// map key is specified same as struct field tag `json` value
// map key is specified same as struct field tag `json` value.
// Play: https://go.dev/play/p/KYGYJqNUBOI
func StructToMap(value any) (map[string]any, error) {
v := reflect.ValueOf(value)
t := reflect.TypeOf(value)
@@ -247,7 +261,8 @@ func StructToMap(value any) (map[string]any, error) {
return result, nil
}
// MapToSlice convert a map to a slice based on iteratee function
// MapToSlice convert map to slice based on iteratee function.
// Play: https://go.dev/play/p/dmX4Ix5V6Wl
func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T) []T {
result := make([]T, 0, len(aMap))
@@ -258,7 +273,8 @@ func MapToSlice[T any, K comparable, V any](aMap map[K]V, iteratee func(K, V) T)
return result
}
// ColorHexToRGB convert hex color to rgb color
// ColorHexToRGB convert hex color to rgb color.
// Play: https://go.dev/play/p/o7_ft-JCJBV
func ColorHexToRGB(colorHex string) (red, green, blue int) {
colorHex = strings.TrimPrefix(colorHex, "#")
color64, err := strconv.ParseInt(colorHex, 16, 32)
@@ -269,7 +285,8 @@ func ColorHexToRGB(colorHex string) (red, green, blue int) {
return color >> 16, (color & 0x00FF00) >> 8, color & 0x0000FF
}
// ColorRGBToHex convert rgb color to hex color
// ColorRGBToHex convert rgb color to hex color.
// Play: https://go.dev/play/p/nzKS2Ro87J1
func ColorRGBToHex(red, green, blue int) string {
r := strconv.FormatInt(int64(red), 16)
g := strconv.FormatInt(int64(green), 16)
@@ -288,7 +305,8 @@ func ColorRGBToHex(red, green, blue int) string {
return "#" + r + g + b
}
// EncodeByte encode data to byte
// EncodeByte encode data to byte slice.
// Play: https://go.dev/play/p/DVmM1G5JfuP
func EncodeByte(data any) ([]byte, error) {
buffer := bytes.NewBuffer(nil)
encoder := gob.NewEncoder(buffer)
@@ -299,7 +317,8 @@ func EncodeByte(data any) ([]byte, error) {
return buffer.Bytes(), nil
}
// DecodeByte decode byte data to target object
// DecodeByte decode byte slice data to target object.
// Play: https://go.dev/play/p/zI6xsmuQRbn
func DecodeByte(data []byte, target any) error {
buffer := bytes.NewBuffer(data)
decoder := gob.NewDecoder(buffer)
+254
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")
ch := ToChannel([]int{1, 2, 3})
val1, _ := <-ch
assert.Equal(1, val1)
val2, _ := <-ch
assert.Equal(2, val2)
val3, _ := <-ch
assert.Equal(3, val3)
assert.Equal(1, <-ch)
assert.Equal(2, <-ch)
assert.Equal(3, <-ch)
_, ok := <-ch
assert.Equal(false, ok)
@@ -254,6 +249,7 @@ func TestDecodeByte(t *testing.T) {
var obj string
byteData := []byte{6, 12, 0, 3, 97, 98, 99}
DecodeByte(byteData, &obj)
err := DecodeByte(byteData, &obj)
assert.IsNil(err)
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"
)
// Base64StdEncode encode string with base64 encoding
// Base64StdEncode encode string with base64 encoding.
// Play: https://go.dev/play/p/VOaUyQUreoK
func Base64StdEncode(s string) string {
return base64.StdEncoding.EncodeToString([]byte(s))
}
// Base64StdDecode decode a base64 encoded string
// Base64StdDecode decode a base64 encoded string.
// Play: https://go.dev/play/p/RWQylnJVgIe
func Base64StdDecode(s string) string {
b, _ := base64.StdEncoding.DecodeString(s)
return string(b)
}
// Md5String return the md5 value of string
// Md5String return the md5 value of string.
// Play: https://go.dev/play/p/1bLcVetbTOI
func Md5String(s string) string {
h := md5.New()
h.Write([]byte(s))
return hex.EncodeToString(h.Sum(nil))
}
// Md5File return the md5 value of file
// Md5File return the md5 value of file.
func Md5File(filename string) (string, error) {
if fileInfo, err := os.Stat(filename); err != nil {
return "", err
@@ -69,49 +72,56 @@ func Md5File(filename string) (string, error) {
return checksum, nil
}
// HmacMd5 return the hmac hash of string use md5
// HmacMd5 return the hmac hash of string use md5.
// Play: https://go.dev/play/p/uef0q1fz53I
func HmacMd5(data, key string) string {
h := hmac.New(md5.New, []byte(key))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha1 return the hmac hash of string use sha1
// HmacSha1 return the hmac hash of string use sha1.
// Play: https://go.dev/play/p/1UI4oQ4WXKM
func HmacSha1(data, key string) string {
h := hmac.New(sha1.New, []byte(key))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha256 return the hmac hash of string use sha256
// HmacSha256 return the hmac hash of string use sha256.
// Play: https://go.dev/play/p/HhpwXxFhhC0
func HmacSha256(data, key string) string {
h := hmac.New(sha256.New, []byte(key))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum([]byte("")))
}
// HmacSha512 return the hmac hash of string use sha512
// HmacSha512 return the hmac hash of string use sha512.
// Play: https://go.dev/play/p/59Od6m4A0Ud
func HmacSha512(data, key string) string {
h := hmac.New(sha512.New, []byte(key))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum([]byte("")))
}
// Sha1 return the sha1 value (SHA-1 hash algorithm) of string
// Sha1 return the sha1 value (SHA-1 hash algorithm) of string.
// Play: https://go.dev/play/p/_m_uoD1deMT
func Sha1(data string) string {
sha1 := sha1.New()
sha1.Write([]byte(data))
return hex.EncodeToString(sha1.Sum([]byte("")))
}
// Sha256 return the sha256 value (SHA256 hash algorithm) of string
// Sha256 return the sha256 value (SHA256 hash algorithm) of string.
// Play: https://go.dev/play/p/tU9tfBMIAr1
func Sha256(data string) string {
sha256 := sha256.New()
sha256.Write([]byte(data))
return hex.EncodeToString(sha256.Sum([]byte("")))
}
// Sha512 return the sha512 value (SHA512 hash algorithm) of string
// Sha512 return the sha512 value (SHA512 hash algorithm) of string.
// Play: https://go.dev/play/p/3WsvLYZxsHa
func Sha512(data string) string {
sha512 := sha512.New()
sha512.Write([]byte(data))
+410
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)
lastLen := lastNum + (lastNum - 1)
heapTree := make([][]string, level, level)
heapTree := make([][]string, level)
for i := 0; i < level; i++ {
heapTree[i] = make([]string, lastLen, lastLen)
heapTree[i] = make([]string, lastLen)
for j := 0; j < lastLen; j++ {
heapTree[i][j] = ""
}
@@ -169,9 +169,9 @@ func (h *MaxHeap[T]) PrintStructure() {
for n := 0; n < lastLen; n++ {
val := heapTree[m][n]
if val == "" {
fmt.Printf(" ")
fmt.Print(" ")
} else {
fmt.Printf(val)
fmt.Print(val)
}
}
fmt.Println()
-2
View File
@@ -30,8 +30,6 @@ func TestMaxHeap_BuildMaxHeap(t *testing.T) {
assert.Equal(expected, heap.data)
assert.Equal(12, heap.Size())
heap.PrintStructure()
}
func TestMaxHeap_Push(t *testing.T) {
+75 -78
View File
@@ -1,13 +1,12 @@
package datastructure
import (
"errors"
"fmt"
"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 {
Head *datastructure.LinkNode[T]
length int
@@ -19,30 +18,30 @@ func NewDoublyLink[T any]() *DoublyLink[T] {
}
// 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)
size := link.Size()
size := dl.Size()
if size == 0 {
link.Head = newNode
link.length++
dl.Head = newNode
dl.length++
return
}
newNode.Next = link.Head
newNode.Next = dl.Head
newNode.Pre = nil
link.Head.Pre = newNode
link.Head = newNode
dl.Head.Pre = newNode
dl.Head = newNode
link.length++
dl.length++
}
// InsertAtTail insert value into doubly linklist at tail index
func (link *DoublyLink[T]) InsertAtTail(value T) {
current := link.Head
func (dl *DoublyLink[T]) InsertAtTail(value T) {
current := dl.Head
if current == nil {
link.InsertAtHead(value)
dl.InsertAtHead(value)
return
}
@@ -55,28 +54,29 @@ func (link *DoublyLink[T]) InsertAtTail(value T) {
newNode.Pre = current
current.Next = newNode
link.length++
dl.length++
}
// InsertAt insert value into doubly linklist at index
func (link *DoublyLink[T]) InsertAt(index int, value T) error {
size := link.length
// param `index` should between [0, length], if index do not meet the conditions, do nothing
func (dl *DoublyLink[T]) InsertAt(index int, value T) {
size := dl.length
if index < 0 || index > size {
return errors.New("param index should between 0 and the length of doubly link.")
return
}
if index == 0 {
link.InsertAtHead(value)
return nil
dl.InsertAtHead(value)
return
}
if index == size {
link.InsertAtTail(value)
return nil
dl.InsertAtTail(value)
return
}
i := 0
current := link.Head
current := dl.Head
for current != nil {
if i == index-1 {
@@ -85,38 +85,36 @@ func (link *DoublyLink[T]) InsertAt(index int, value T) error {
newNode.Pre = current
current.Next = newNode
link.length++
dl.length++
return nil
return
}
i++
current = current.Next
}
return errors.New("doubly link list no exist")
}
// DeleteAtHead delete value in doubly linklist at head index
func (link *DoublyLink[T]) DeleteAtHead() error {
if link.Head == nil {
return errors.New("doubly link list no exist")
}
current := link.Head
link.Head = current.Next
link.Head.Pre = nil
link.length--
return nil
func (dl *DoublyLink[T]) DeleteAtHead() {
if dl.Head == nil {
return
}
// DeleteAtTail delete value in doubly linklist at tail index
func (link *DoublyLink[T]) DeleteAtTail() error {
if link.Head == nil {
return errors.New("doubly link list no exist")
current := dl.Head
dl.Head = current.Next
dl.Head.Pre = nil
dl.length--
}
current := link.Head
// DeleteAtTail delete value in doubly linklist at tail
func (dl *DoublyLink[T]) DeleteAtTail() {
if dl.Head == nil {
return
}
current := dl.Head
if current.Next == nil {
return link.DeleteAtHead()
dl.DeleteAtHead()
}
for current.Next.Next != nil {
@@ -124,45 +122,44 @@ func (link *DoublyLink[T]) DeleteAtTail() error {
}
current.Next = nil
link.length--
return nil
dl.length--
}
// DeleteAt delete value in doubly linklist at index
func (link *DoublyLink[T]) DeleteAt(index int) error {
if link.Head == nil {
return errors.New("doubly link list no exist")
// param `index` should be [0, len(DoublyLink)-1]
func (dl *DoublyLink[T]) DeleteAt(index int) {
if dl.Head == nil {
return
}
current := link.Head
current := dl.Head
if current.Next == nil || index == 0 {
return link.DeleteAtHead()
dl.DeleteAtHead()
}
if index == link.length-1 {
return link.DeleteAtTail()
if index == dl.length-1 {
dl.DeleteAtTail()
}
if index < 0 || index > link.length-1 {
return errors.New("param index should between 0 and link size -1.")
if index < 0 || index > dl.length-1 {
return
}
i := 0
for current != nil {
if i == index-1 {
current.Next = current.Next.Next
link.length--
return nil
dl.length--
return
}
i++
current = current.Next
}
return errors.New("delete error")
}
// Reverse the linked list
func (link *DoublyLink[T]) Reverse() {
current := link.Head
func (dl *DoublyLink[T]) Reverse() {
current := dl.Head
var temp *datastructure.LinkNode[T]
for current != nil {
@@ -173,20 +170,20 @@ func (link *DoublyLink[T]) Reverse() {
}
if temp != nil {
link.Head = temp.Pre
dl.Head = temp.Pre
}
}
// GetMiddleNode return node at middle index of linked list
func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
if link.Head == nil {
func (dl *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
if dl.Head == nil {
return nil
}
if link.Head.Next == nil {
return link.Head
if dl.Head.Next == nil {
return dl.Head
}
fast := link.Head
slow := link.Head
fast := dl.Head
slow := dl.Head
for fast != nil {
fast = fast.Next
@@ -202,14 +199,14 @@ func (link *DoublyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
}
// Size return the count of doubly linked list
func (link *DoublyLink[T]) Size() int {
return link.length
func (dl *DoublyLink[T]) Size() int {
return dl.length
}
// Values return slice of all doubly linklist node value
func (link *DoublyLink[T]) Values() []T {
func (dl *DoublyLink[T]) Values() []T {
result := []T{}
current := link.Head
current := dl.Head
for current != nil {
result = append(result, current.Value)
current = current.Next
@@ -218,8 +215,8 @@ func (link *DoublyLink[T]) Values() []T {
}
// Print all nodes info of a linked list
func (link *DoublyLink[T]) Print() {
current := link.Head
func (dl *DoublyLink[T]) Print() {
current := dl.Head
info := "[ "
for current != nil {
info += fmt.Sprintf("%+v, ", current)
@@ -229,13 +226,13 @@ func (link *DoublyLink[T]) Print() {
fmt.Println(info)
}
// IsEmpty checks if link is empty or not
func (link *DoublyLink[T]) IsEmpty() bool {
return link.length == 0
// IsEmpty checks if dl is empty or not
func (dl *DoublyLink[T]) IsEmpty() bool {
return dl.length == 0
}
// Clear all nodes in doubly linklist
func (link *DoublyLink[T]) Clear() {
link.Head = nil
link.length = 0
func (dl *DoublyLink[T]) Clear() {
dl.Head = nil
dl.length = 0
}
+5 -18
View File
@@ -41,29 +41,24 @@ func TestDoublyLink_InsertAt(t *testing.T) {
link := NewDoublyLink[int]()
err := link.InsertAt(1, 1)
assert.IsNotNil(err)
link.InsertAt(1, 1) //do nothing
link.InsertAt(0, 1)
link.InsertAt(1, 2)
link.InsertAt(2, 4)
link.InsertAt(2, 3)
link.Print()
expected := []int{1, 2, 3, 4}
values := link.Values()
assert.Equal(expected, values)
}
func TestDoublyLink_DeleteAtHead(t *testing.T) {
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtHead")
link := NewDoublyLink[int]()
err := link.DeleteAtHead()
assert.IsNotNil(err)
link.DeleteAtHead()
link.InsertAtTail(1)
link.InsertAtTail(2)
@@ -71,7 +66,6 @@ func TestDoublyLink_DeleteAtHead(t *testing.T) {
link.InsertAtTail(4)
link.DeleteAtHead()
link.Print()
expected := []int{2, 3, 4}
values := link.Values()
@@ -83,8 +77,7 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAtTail")
link := NewDoublyLink[int]()
err := link.DeleteAtTail()
assert.IsNotNil(err)
link.DeleteAtTail()
link.InsertAtTail(1)
link.InsertAtTail(2)
@@ -92,7 +85,6 @@ func TestDoublyLink_DeleteAtTail(t *testing.T) {
link.InsertAtTail(4)
link.DeleteAtTail()
link.Print()
expected := []int{1, 2, 3}
values := link.Values()
@@ -104,8 +96,7 @@ func TestDoublyLink_DeleteAt(t *testing.T) {
assert := internal.NewAssert(t, "TestDoublyLink_DeleteAt")
link := NewDoublyLink[int]()
err := link.DeleteAt(0)
assert.IsNotNil(err)
link.DeleteAt(0)
link.InsertAtTail(1)
link.InsertAtTail(2)
@@ -113,11 +104,7 @@ func TestDoublyLink_DeleteAt(t *testing.T) {
link.InsertAtTail(4)
link.InsertAtTail(5)
err = link.DeleteAt(5)
assert.IsNotNil(err)
err = link.DeleteAt(0)
assert.IsNil(err)
link.DeleteAt(0)
assert.Equal([]int{2, 3, 4, 5}, link.Values())
link.DeleteAt(3)
+74 -79
View File
@@ -1,14 +1,13 @@
package datastructure
import (
"errors"
"fmt"
"reflect"
"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 {
Head *datastructure.LinkNode[T]
length int
@@ -20,18 +19,18 @@ func NewSinglyLink[T any]() *SinglyLink[T] {
}
// 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.Next = link.Head
link.Head = newNode
link.length++
newNode.Next = sl.Head
sl.Head = newNode
sl.length++
}
// InsertAtTail insert value into singly linklist at tail index
func (link *SinglyLink[T]) InsertAtTail(value T) {
current := link.Head
func (sl *SinglyLink[T]) InsertAtTail(value T) {
current := sl.Head
if current == nil {
link.InsertAtHead(value)
sl.InsertAtHead(value)
return
}
@@ -43,65 +42,63 @@ func (link *SinglyLink[T]) InsertAtTail(value T) {
newNode.Next = nil
current.Next = newNode
link.length++
sl.length++
}
// InsertAt insert value into singly linklist at index
func (link *SinglyLink[T]) InsertAt(index int, value T) error {
size := link.length
// param `index` should between [0, len(SinglyLink)], if index do not meet the conditions, do nothing
func (sl *SinglyLink[T]) InsertAt(index int, value T) {
size := sl.length
if index < 0 || index > size {
return errors.New("param index should between 0 and the length of singly link.")
return
}
if index == 0 {
link.InsertAtHead(value)
return nil
sl.InsertAtHead(value)
return
}
if index == size {
link.InsertAtTail(value)
return nil
sl.InsertAtTail(value)
return
}
i := 0
current := link.Head
current := sl.Head
for current != nil {
if i == index-1 {
newNode := datastructure.NewLinkNode(value)
newNode.Next = current.Next
current.Next = newNode
link.length++
return nil
sl.length++
return
}
i++
current = current.Next
}
return errors.New("singly link list no exist")
}
// DeleteAtHead delete value in singly linklist at head index
func (link *SinglyLink[T]) DeleteAtHead() error {
if link.Head == nil {
return errors.New("singly link list no exist")
}
current := link.Head
link.Head = current.Next
link.length--
return nil
func (sl *SinglyLink[T]) DeleteAtHead() {
if sl.Head == nil {
return
}
// DeleteAtTail delete value in singly linklist at tail index
func (link *SinglyLink[T]) DeleteAtTail() error {
if link.Head == nil {
return errors.New("singly link list no exist")
current := sl.Head
sl.Head = current.Next
sl.length--
}
current := link.Head
// DeleteAtTail delete value in singly linklist at tail
func (sl *SinglyLink[T]) DeleteAtTail() {
if sl.Head == nil {
return
}
current := sl.Head
if current.Next == nil {
return link.DeleteAtHead()
sl.DeleteAtHead()
}
for current.Next.Next != nil {
@@ -109,68 +106,66 @@ func (link *SinglyLink[T]) DeleteAtTail() error {
}
current.Next = nil
link.length--
return nil
sl.length--
}
// DeleteAt delete value in singly linklist at index
func (link *SinglyLink[T]) DeleteAt(index int) error {
if link.Head == nil {
return errors.New("singly link list no exist")
// param `index` should be [0, len(SinglyLink)-1]
func (sl *SinglyLink[T]) DeleteAt(index int) {
if sl.Head == nil {
return
}
current := link.Head
current := sl.Head
if current.Next == nil || index == 0 {
return link.DeleteAtHead()
sl.DeleteAtHead()
}
if index == link.length-1 {
return link.DeleteAtTail()
if index == sl.length-1 {
sl.DeleteAtTail()
}
if index < 0 || index > link.length-1 {
return errors.New("param index should between 0 and link size -1.")
if index < 0 || index > sl.length-1 {
return
}
i := 0
for current != nil {
if i == index-1 {
current.Next = current.Next.Next
link.length--
return nil
sl.length--
return
}
i++
current = current.Next
}
return errors.New("delete error")
}
// DeleteValue delete value in singly linklist
func (link *SinglyLink[T]) DeleteValue(value T) {
if link.Head == nil {
func (sl *SinglyLink[T]) DeleteValue(value T) {
if sl.Head == nil {
return
}
dummyHead := datastructure.NewLinkNode(value)
dummyHead.Next = link.Head
dummyHead.Next = sl.Head
current := dummyHead
for current.Next != nil {
if reflect.DeepEqual(current.Next.Value, value) {
current.Next = current.Next.Next
link.length--
sl.length--
} else {
current = current.Next
}
}
link.Head = dummyHead.Next
sl.Head = dummyHead.Next
}
// Reverse the linked list
func (link *SinglyLink[T]) Reverse() {
func (sl *SinglyLink[T]) Reverse() {
var pre, next *datastructure.LinkNode[T]
current := link.Head
current := sl.Head
for current != nil {
next = current.Next
@@ -179,19 +174,19 @@ func (link *SinglyLink[T]) Reverse() {
current = next
}
link.Head = pre
sl.Head = pre
}
// GetMiddleNode return node at middle index of linked list
func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
if link.Head == nil {
func (sl *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
if sl.Head == nil {
return nil
}
if link.Head.Next == nil {
return link.Head
if sl.Head.Next == nil {
return sl.Head
}
fast := link.Head
slow := link.Head
fast := sl.Head
slow := sl.Head
for fast != nil {
fast = fast.Next
@@ -207,14 +202,14 @@ func (link *SinglyLink[T]) GetMiddleNode() *datastructure.LinkNode[T] {
}
// Size return the count of singly linked list
func (link *SinglyLink[T]) Size() int {
return link.length
func (sl *SinglyLink[T]) Size() int {
return sl.length
}
// Values return slice of all singly linklist node value
func (link *SinglyLink[T]) Values() []T {
func (sl *SinglyLink[T]) Values() []T {
result := []T{}
current := link.Head
current := sl.Head
for current != nil {
result = append(result, current.Value)
current = current.Next
@@ -222,20 +217,20 @@ func (link *SinglyLink[T]) Values() []T {
return result
}
// IsEmpty checks if link is empty or not
func (link *SinglyLink[T]) IsEmpty() bool {
return link.length == 0
// IsEmpty checks if sl is empty or not
func (sl *SinglyLink[T]) IsEmpty() bool {
return sl.length == 0
}
// Clear all the node in singly linklist
func (link *SinglyLink[T]) Clear() {
link.Head = nil
link.length = 0
func (sl *SinglyLink[T]) Clear() {
sl.Head = nil
sl.length = 0
}
// Print all nodes info of a linked list
func (link *SinglyLink[T]) Print() {
current := link.Head
func (sl *SinglyLink[T]) Print() {
current := sl.Head
info := "[ "
for current != nil {
info += fmt.Sprintf("%+v, ", current)
+8 -31
View File
@@ -41,25 +41,12 @@ func TestSinglyLink_InsertAt(t *testing.T) {
link := NewSinglyLink[int]()
err := link.InsertAt(1, 1)
assert.IsNotNil(err)
link.InsertAt(1, 1) //do nothing
err = link.InsertAt(0, 1)
if err != nil {
t.FailNow()
}
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.InsertAt(0, 1)
link.InsertAt(1, 2)
link.InsertAt(2, 4)
link.InsertAt(2, 3)
link.Print()
@@ -73,8 +60,8 @@ func TestSinglyLink_DeleteAtHead(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtHead")
link := NewSinglyLink[int]()
err := link.DeleteAtHead()
assert.IsNotNil(err)
link.DeleteAtHead()
link.InsertAtTail(1)
link.InsertAtTail(2)
@@ -94,8 +81,6 @@ func TestSinglyLink_DeleteAtTail(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAtTail")
link := NewSinglyLink[int]()
err := link.DeleteAtTail()
assert.IsNotNil(err)
link.InsertAtTail(1)
link.InsertAtTail(2)
@@ -103,7 +88,6 @@ func TestSinglyLink_DeleteAtTail(t *testing.T) {
link.InsertAtTail(4)
link.DeleteAtTail()
link.Print()
expected := []int{1, 2, 3}
values := link.Values()
@@ -133,8 +117,6 @@ func TestSinglyLink_DeleteAt(t *testing.T) {
assert := internal.NewAssert(t, "TestSinglyLink_DeleteAt")
link := NewSinglyLink[int]()
err := link.DeleteAt(0)
assert.IsNotNil(err)
link.InsertAtTail(1)
link.InsertAtTail(2)
@@ -142,11 +124,7 @@ func TestSinglyLink_DeleteAt(t *testing.T) {
link.InsertAtTail(4)
link.InsertAtTail(5)
err = link.DeleteAt(5)
assert.IsNotNil(err)
err = link.DeleteAt(0)
assert.IsNil(err)
link.DeleteAt(0)
assert.Equal([]int{2, 3, 4, 5}, link.Values())
link.DeleteAt(3)
@@ -167,7 +145,6 @@ func TestSinglyLink_Reverse(t *testing.T) {
link.InsertAtTail(4)
link.Reverse()
link.Print()
assert.Equal([]int{4, 3, 2, 1}, link.Values())
}
+32 -32
View File
@@ -8,17 +8,17 @@ import (
"reflect"
)
// List is a linear table, implemented with slice
// List is a linear table, implemented with slice.
type List[T any] struct {
data []T
}
// NewList return a pointer of List
// NewList return a pointer of List.
func NewList[T any](data []T) *List[T] {
return &List[T]{data: data}
}
// Data return list data
// Data return list data.
func (l *List[T]) Data() []T {
return l.data
}
@@ -31,7 +31,7 @@ func (l *List[T]) ValueOf(index int) (*T, bool) {
return &l.data[index], true
}
// IndexOf returns the index of value. if not found return -1
// IndexOf returns the index of value. if not found return -1.
func (l *List[T]) IndexOf(value T) int {
index := -1
data := l.data
@@ -45,7 +45,7 @@ func (l *List[T]) IndexOf(value T) int {
}
// LastIndexOf returns the index of the last occurrence of the value in this list.
// if not found return -1
// if not found return -1.
func (l *List[T]) LastIndexOf(value T) int {
index := -1
data := l.data
@@ -59,7 +59,7 @@ func (l *List[T]) LastIndexOf(value T) int {
}
// IndexOfFunc returns the first index satisfying f(v)
// if not found return -1
// if not found return -1.
func (l *List[T]) IndexOfFunc(f func(T) bool) int {
index := -1
data := l.data
@@ -73,7 +73,7 @@ func (l *List[T]) IndexOfFunc(f func(T) bool) int {
}
// LastIndexOfFunc returns the index of the last occurrence of the value in this list satisfying f(data[i])
// if not found return -1
// if not found return -1.
func (l *List[T]) LastIndexOfFunc(f func(T) bool) int {
index := -1
data := l.data
@@ -86,7 +86,7 @@ func (l *List[T]) LastIndexOfFunc(f func(T) bool) int {
return index
}
// Contain checks if the value in the list or not
// Contain checks if the value in the list or not.
func (l *List[T]) Contain(value T) bool {
data := l.data
for _, v := range data {
@@ -97,22 +97,22 @@ func (l *List[T]) Contain(value T) bool {
return false
}
// Push append value to the list data
// Push append value to the list data.
func (l *List[T]) Push(value T) {
l.data = append(l.data, value)
}
// InsertAtFirst insert value into list at first index
// InsertAtFirst insert value into list at first index.
func (l *List[T]) InsertAtFirst(value T) {
l.InsertAt(0, value)
}
// InsertAtLast insert value into list at last index
// InsertAtLast insert value into list at last index.
func (l *List[T]) InsertAtLast(value T) {
l.InsertAt(len(l.data), value)
}
// InsertAt insert value into list at index
// InsertAt insert value into list at index.
func (l *List[T]) InsertAt(index int, value T) {
data := l.data
size := len(data)
@@ -123,7 +123,7 @@ func (l *List[T]) InsertAt(index int, value T) {
l.data = append(data[:index], append([]T{value}, data[index:]...)...)
}
// PopFirst delete the first value of list and return it
// PopFirst delete the first value of list and return it.
func (l *List[T]) PopFirst() (*T, bool) {
if len(l.data) == 0 {
return nil, false
@@ -135,7 +135,7 @@ func (l *List[T]) PopFirst() (*T, bool) {
return &v, true
}
// PopLast delete the last value of list and return it
// PopLast delete the last value of list and return it.
func (l *List[T]) PopLast() (*T, bool) {
size := len(l.data)
if size == 0 {
@@ -148,7 +148,7 @@ func (l *List[T]) PopLast() (*T, bool) {
return &v, true
}
// DeleteAt delete the value of list at index
// DeleteAt delete the value of list at index.
func (l *List[T]) DeleteAt(index int) {
data := l.data
size := len(data)
@@ -156,7 +156,7 @@ func (l *List[T]) DeleteAt(index int) {
return
}
if index == size-1 {
data = append(data[:index])
data = data[:index]
} else {
data = append(data[:index], data[index+1:]...)
}
@@ -174,7 +174,7 @@ func (l *List[T]) DeleteIf(f func(T) bool) int {
continue
}
if index == size-1 {
data = append(data[:index])
data = data[:index]
} else {
data = append(data[:index], data[index+1:]...)
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:]...)...)
}
// Equal compare list to other list, use reflect.DeepEqual
// Equal compare list to other list, use reflect.DeepEqual.
func (l *List[T]) Equal(other *List[T]) bool {
if len(l.data) != len(other.data) {
return false
@@ -214,17 +214,17 @@ func (l *List[T]) Equal(other *List[T]) bool {
return true
}
// IsEmpty check if the list is empty or not
// IsEmpty check if the list is empty or not.
func (l *List[T]) IsEmpty() bool {
return len(l.data) == 0
}
// Clear the data of list
// Clear the data of list.
func (l *List[T]) Clear() {
l.data = make([]T, 0, 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] {
cl := NewList(make([]T, len(l.data)))
copy(cl.data, l.data)
@@ -232,10 +232,10 @@ func (l *List[T]) Clone() *List[T] {
return cl
}
// Merge two list, return new list, don't change original list
// Merge two list, return new list, don't change original list.
func (l *List[T]) Merge(other *List[T]) *List[T] {
l1, l2 := len(l.data), len(other.data)
ml := NewList(make([]T, l1+l2, l1+l2))
ml := NewList(make([]T, l1+l2))
data := append([]T{}, append(l.data, other.data...)...)
ml.data = data
@@ -243,17 +243,17 @@ func (l *List[T]) Merge(other *List[T]) *List[T] {
return ml
}
// Size return number of list data items
// Size return number of list data items.
func (l *List[T]) Size() int {
return len(l.data)
}
// Cap return cap of the inner data
// Cap return cap of the inner data.
func (l *List[T]) Cap() int {
return cap(l.data)
}
// Swap the value of index i and j in list
// Swap the value of index i and j in list.
func (l *List[T]) Swap(i, j int) {
size := len(l.data)
if i < 0 || i >= size || j < 0 || j >= size {
@@ -262,19 +262,19 @@ func (l *List[T]) Swap(i, j int) {
l.data[i], l.data[j] = l.data[j], l.data[i]
}
// Reverse the item order of list
// Reverse the item order of list.
func (l *List[T]) Reverse() {
for i, j := 0, len(l.data)-1; i < j; i, j = i+1, j-1 {
l.data[i], l.data[j] = l.data[j], l.data[i]
}
}
// Unique remove duplicate items in list
// Unique remove duplicate items in list.
func (l *List[T]) Unique() {
data := l.data
size := len(data)
uniqueData := make([]T, 0, 0)
uniqueData := make([]T, 0)
for i := 0; i < size; i++ {
value := data[i]
skip := true
@@ -303,9 +303,9 @@ func (l *List[T]) Union(other *List[T]) *List[T] {
return result
}
// Intersection creates a new list whose element both be contained in list l and other
// Intersection creates a new list whose element both be contained in list l and other.
func (l *List[T]) Intersection(other *List[T]) *List[T] {
result := NewList(make([]T, 0, 0))
result := NewList(make([]T, 0))
for _, v := range l.data {
if other.Contain(v) {
-7
View File
@@ -18,8 +18,6 @@ func TestArrayQueue_Enqueue(t *testing.T) {
data := queue.Data()
size := queue.Size()
queue.Print()
assert.Equal(expected, data)
assert.Equal(3, size)
}
@@ -35,7 +33,6 @@ func TestArrayQueue_Dequeue(t *testing.T) {
val, ok := queue.Dequeue()
assert.Equal(true, ok)
queue.Print()
assert.Equal(1, val)
assert.Equal([]int{2, 3}, queue.Data())
}
@@ -50,8 +47,6 @@ func TestArrayQueue_Front(t *testing.T) {
val := queue.Front()
queue.Print()
assert.Equal(1, val)
assert.Equal([]int{1, 2, 3}, queue.Data())
}
@@ -66,8 +61,6 @@ func TestArrayQueue_Back(t *testing.T) {
val := queue.Back()
queue.Print()
assert.Equal(3, val)
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")
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(5, queue.Size())
err := queue.Enqueue(6)
err = queue.Enqueue(6)
assert.IsNotNil(err)
}
func TestCircularQueue_Dequeue(t *testing.T) {
assert := internal.NewAssert(t, "TestCircularQueue_DeQueue")
queue := NewCircularQueue[int](6)
queue := NewCircularQueue[int](4)
assert.Equal(true, queue.IsEmpty())
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
queue.Enqueue(4)
queue.Enqueue(5)
err := queue.Enqueue(1)
assert.IsNil(err)
err = queue.Enqueue(2)
assert.IsNil(err)
err = queue.Enqueue(3)
assert.IsNil(err)
val, err := queue.Dequeue()
assert.IsNil(err)
@@ -43,11 +55,7 @@ func TestCircularQueue_Dequeue(t *testing.T) {
assert.Equal(false, queue.IsFull())
val, _ = queue.Dequeue()
queue.Print()
assert.Equal(2, *val)
queue.Enqueue(6)
queue.Print()
assert.Equal(false, queue.IsFull())
}
@@ -55,55 +63,52 @@ func TestCircularQueue_Front(t *testing.T) {
assert := internal.NewAssert(t, "TestCircularQueue_Front")
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()
queue.Dequeue()
queue.Enqueue(6)
queue.Enqueue(7)
err = queue.Enqueue(2)
assert.IsNil(err)
queue.Print()
err = queue.Enqueue(3)
assert.IsNil(err)
val := queue.Front()
assert.Equal(3, val)
assert.Equal(5, queue.Size())
assert.IsNil(err)
assert.Equal(1, val)
assert.Equal(3, queue.Size())
}
func TestCircularQueue_Back(t *testing.T) {
assert := internal.NewAssert(t, "TestCircularQueue_Back")
queue := NewCircularQueue[int](6)
queue := NewCircularQueue[int](3)
assert.Equal(true, queue.IsEmpty())
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
queue.Enqueue(4)
queue.Enqueue(5)
err := queue.Enqueue(1)
assert.IsNil(err)
queue.Print()
assert.Equal(5, queue.Back())
err = queue.Enqueue(2)
assert.IsNil(err)
queue.Dequeue()
queue.Dequeue()
queue.Enqueue(6)
queue.Enqueue(7)
assert.Equal(2, queue.Back())
queue.Print()
assert.Equal(7, queue.Back())
val, _ := queue.Dequeue()
assert.Equal(1, *val)
err = queue.Enqueue(3)
assert.IsNil(err)
assert.Equal(3, queue.Back())
}
func TestCircularQueue_Contain(t *testing.T) {
assert := internal.NewAssert(t, "TestCircularQueue_Contain")
queue := NewCircularQueue[int](2)
queue.Enqueue(1)
err := queue.Enqueue(1)
assert.IsNil(err)
assert.Equal(true, queue.Contain(1))
assert.Equal(false, queue.Contain(2))
}
@@ -115,7 +120,9 @@ func TestCircularQueue_Clear(t *testing.T) {
assert.Equal(true, queue.IsEmpty())
assert.Equal(0, queue.Size())
queue.Enqueue(1)
err := queue.Enqueue(1)
assert.IsNil(err)
assert.Equal(false, queue.IsEmpty())
assert.Equal(1, queue.Size())
@@ -127,22 +134,12 @@ func TestCircularQueue_Clear(t *testing.T) {
func TestCircularQueue_Data(t *testing.T) {
assert := internal.NewAssert(t, "TestCircularQueue_Data")
queue := NewCircularQueue[int](6)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Enqueue(3)
queue.Enqueue(4)
queue.Enqueue(5)
queue := NewCircularQueue[int](3)
err := queue.Enqueue(1)
assert.IsNil(err)
queue.Print()
assert.Equal([]int{1, 2, 3, 4, 5}, queue.Data())
queue.Dequeue()
queue.Dequeue()
queue.Enqueue(6)
queue.Enqueue(7)
queue.Print()
assert.Equal([]int{3, 4, 5, 6, 7}, queue.Data())
err = queue.Enqueue(2)
assert.IsNil(err)
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(3)
queue.Print()
assert.Equal([]int{1, 2, 3}, queue.Data())
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")
comparator := &intComparator{}
pq := NewPriorityQueue[int](10, comparator)
pq := NewPriorityQueue[int](3, comparator)
assert.Equal(true, pq.IsEmpty())
assert.Equal(false, pq.IsFull())
for i := 1; i < 11; i++ {
pq.Enqueue(i)
}
err := pq.Enqueue(1)
assert.IsNil(err)
err = pq.Enqueue(2)
assert.IsNil(err)
err = pq.Enqueue(3)
assert.IsNil(err)
assert.Equal(true, pq.IsFull())
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")
comparator := &intComparator{}
pq := NewPriorityQueue[int](10, comparator)
pq := NewPriorityQueue[int](3, comparator)
_, ok := pq.Dequeue()
assert.Equal(false, ok)
for i := 1; i < 11; i++ {
pq.Enqueue(i)
}
err := pq.Enqueue(1)
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()
assert.Equal(true, ok)
assert.Equal(10, val)
assert.Equal([]int{9, 8, 6, 7, 3, 2, 5, 1, 4}, pq.Data())
assert.Equal(9, pq.Size())
assert.Equal(3, val)
}
-2
View File
@@ -14,8 +14,6 @@ func TestLinkedStack_Push(t *testing.T) {
stack.Push(2)
stack.Push(3)
stack.Print()
expected := []int{3, 2, 1}
values := stack.Data()
size := stack.Size()
+1 -11
View File
@@ -27,8 +27,6 @@ func TestBSTree_Insert(t *testing.T) {
bstree.Insert(5)
bstree.Insert(2)
bstree.Insert(4)
bstree.Print()
}
func TestBSTree_PreOrderTraverse(t *testing.T) {
@@ -86,8 +84,6 @@ func TestBSTree_LevelOrderTraverse(t *testing.T) {
bstree.Insert(2)
bstree.Insert(4)
bstree.Print()
acturl := bstree.LevelOrderTraverse()
t.Log(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(4)
bstree.Print()
bstree.Delete(4)
bstree.Print()
acturl1 := bstree.InOrderTraverse()
t.Log(acturl1)
assert.Equal([]int{2, 5, 6, 7}, acturl1)
@@ -129,8 +123,6 @@ func TestBSTree_Depth(t *testing.T) {
bstree.Insert(2)
bstree.Insert(4)
bstree.Print()
assert.Equal(bstree.Depth(), 4)
}
@@ -150,8 +142,6 @@ func TestBSTree_IsSubTree(t *testing.T) {
subTree.Insert(4)
subTree.Insert(6)
subTree.Print()
assert.Equal(true, superTree.HasSubTree(subTree))
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
}
func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
if node == nil {
return
}
// func preOrderPrint[T any](node *datastructure.TreeNode[T]) {
// if node == nil {
// return
// }
fmt.Printf("%v, ", node.Value)
preOrderPrint(node.Left)
preOrderPrint(node.Right)
}
// fmt.Printf("%v, ", node.Value)
// preOrderPrint(node.Left)
// preOrderPrint(node.Right)
// }
func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
if node == nil {
return
}
// func postOrderPrint[T any](node *datastructure.TreeNode[T]) {
// if node == nil {
// return
// }
preOrderPrint(node.Left)
preOrderPrint(node.Right)
fmt.Printf("%v, ", node.Value)
}
// postOrderPrint(node.Left)
// postOrderPrint(node.Right)
// fmt.Printf("%v, ", node.Value)
// }
func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
if node == nil {
return
}
// func inOrderPrint[T any](node *datastructure.TreeNode[T]) {
// if node == nil {
// return
// }
inOrderPrint(node.Left)
fmt.Printf("%v, ", node.Value)
inOrderPrint(node.Right)
}
// inOrderPrint(node.Left)
// fmt.Printf("%v, ", node.Value)
// inOrderPrint(node.Right)
// }
func levelOrderTraverse[T any](root *datastructure.TreeNode[T], traversal *[]T) {
var q []*datastructure.TreeNode[T] // queue
+8 -2
View File
@@ -570,6 +570,8 @@ func main() {
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
func (l *LRUCache[K, V]) Get(key K) (V, bool)
func (l *LRUCache[K, V]) Put(key K, value V)
func (l *LRUCache[K, V]) Delete(key K) bool
func (l *LRUCache[K, V]) Len() int
```
<b>Example:</b>
@@ -586,10 +588,14 @@ func main() {
cache.Put(1, 1)
cache.Put(2, 2)
cache.Put(3, 3)
_, ok := cache.Get(0) // ok -> false
fmt.Println(cache.Len()) // 3
v, ok := cache.Get(1) // v->1, ok->true
v, ok := cache.Get(1)
fmt.Println(v, ok) // 1 true
ok = cache.Delete(1)
fmt.Println(ok) // true
}
```
+8 -2
View File
@@ -570,6 +570,8 @@ func main() {
func NewLRUCache[K comparable, V any](capacity int) *LRUCache[K, V]
func (l *LRUCache[K, V]) Get(key K) (V, bool)
func (l *LRUCache[K, V]) Put(key K, value V)
func (l *LRUCache[K, V]) Delete(key K) bool
func (l *LRUCache[K, V]) Len() int
```
<b>Example:</b>
@@ -586,10 +588,14 @@ func main() {
cache.Put(1, 1)
cache.Put(2, 2)
cache.Put(3, 3)
_, ok := cache.Get(0) // ok -> false
fmt.Println(cache.Len()) // 3
v, ok := cache.Get(1) // v->1, ok->true
v, ok := cache.Get(1)
fmt.Println(v, ok) // 1 true
ok = cache.Delete(1)
fmt.Println(ok) // true
}
```
+125 -62
View File
@@ -38,13 +38,13 @@ import (
## Channel
### <span id="NewChannel">NewChannel</span>
<p>return a Channel pointer instance.</p>
<p>Create a Channel pointer instance.</p>
<b>Signature:</b>
```go
type Channel struct {}
func NewChannel() *Channel
type Channel[T any] struct
func NewChannel[T any]() *Channel[T]
```
<b>Example:</b>
@@ -57,7 +57,7 @@ import (
)
func main() {
c := concurrency.NewChannel()
c := concurrency.NewChannel[int]()
}
```
@@ -70,7 +70,7 @@ func main() {
<b>Signature:</b>
```go
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
```
<b>Example:</b>
@@ -87,25 +87,30 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
genVals := func() <-chan <-chan any {
chanStream := make(chan (<-chan any))
c := concurrency.NewChannel[int]()
genVals := func() <-chan <-chan int {
out := make(chan (<-chan int))
go func() {
defer close(chanStream)
for i := 0; i < 10; i++ {
stream := make(chan any, 1)
defer close(out)
for i := 1; i <= 5; i++ {
stream := make(chan int, 1)
stream <- i
close(stream)
chanStream <- stream
out <- stream
}
}()
return chanStream
return out
}
index := 0
for val := range c.Bridge(ctx, genVals()) {
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
for v := range c.Bridge(ctx, genVals()) {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
// 4
// 5
}
```
@@ -114,12 +119,12 @@ func main() {
### <span id="FanIn">FanIn</span>
<p>merge multiple channels into one channel until cancel the context.</p>
<p>Merge multiple channels into one channel until cancel the context.</p>
<b>Signature:</b>
```go
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
```
<b>Example:</b>
@@ -136,17 +141,17 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
channels := make([]<-chan any, 3)
c := concurrency.NewChannel[int]()
channels := make([]<-chan int, 2)
for i := 0; i < 3; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
for i := 0; i < 2; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
}
mergedChannel := c.FanIn(ctx, channels...)
chs := c.FanIn(ctx, channels...)
for val := range mergedChannel {
fmt.Println("\t%d\n", val) //1,2,1,0,0,1,0,2,2 (order not for sure)
for v := range chs {
fmt.Println(v) //1 1 0 0 or 0 0 1 1
}
}
```
@@ -154,12 +159,12 @@ func main() {
### <span id="Repeat">Repeat</span>
<p>Return a chan, put param `values` into the chan repeatly until cancel the context.</p>
<p>Create channel, put values into the channel repeatly until cancel the context.</p>
<b>Signature:</b>
```go
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
```
<b>Example:</b>
@@ -176,26 +181,68 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
for v := range intStream {
fmt.Println(v) //1, 2, 1, 2, 1
fmt.Println(v)
}
// Output:
// 1
// 2
// 1
// 2
}
```
### <span id="Generate">Generate</span>
<p>Creates a channel, then put values into the channel.</p>
<b>Signature:</b>
```go
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
```
<b>Example:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
intStream := c.Generate(ctx, 1, 2, 3)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
// Output:
// 1
// 2
// 3
}
```
### <span id="RepeatFn">RepeatFn</span>
<p>Return a chan, excutes fn repeatly, and put the result into retruned chan until cancel context.</p>
<p>Create a channel, excutes fn repeatly, and put the result into the channel, until close context.</p>
<b>Signature:</b>
```go
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
```
<b>Example:</b>
@@ -212,16 +259,20 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() any {
s := "a"
return s
fn := func() string {
return "hello"
}
c := concurrency.NewChannel()
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
for v := range dataStream {
fmt.Println(v) //a, a, a
c := concurrency.NewChannel[string]()
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
for v := range intStream {
fmt.Println(v)
}
// Output:
// hello
// hello
// hello
}
```
@@ -234,7 +285,7 @@ func main() {
<b>Signature:</b>
```go
func (c *Channel) Or(channels ...<-chan any) <-chan any
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
```
<b>Example:</b>
@@ -249,7 +300,7 @@ import (
func main() {
sig := func(after time.Duration) <-chan any {
c := make(chan interface{})
c := make(chan any)
go func() {
defer close(c)
time.Sleep(after)
@@ -259,13 +310,11 @@ func main() {
start := time.Now()
c := concurrency.NewChannel()
c := concurrency.NewChannel[any]()
<-c.Or(
sig(1*time.Second),
sig(2*time.Second),
sig(3*time.Second),
sig(4*time.Second),
sig(5*time.Second),
)
fmt.Println("done after %v", time.Since(start)) //1.003s
@@ -282,7 +331,7 @@ func main() {
<b>Signature:</b>
```go
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
```
<b>Example:</b>
@@ -299,12 +348,16 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
for val := range c.OrDone(ctx, intStream) {
fmt.Println(val) //1
for v := range c.OrDone(ctx, intStream) {
fmt.Println(v)
}
// Output:
// 1
// 1
// 1
}
```
@@ -313,12 +366,12 @@ func main() {
### <span id="Take">Take</span>
<p>Return a chan whose values are tahken from another chan until cancel context.</p>
<p>Create a channel whose values are taken from another channel with limit number.</p>
<b>Signature:</b>
```go
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
```
<b>Example:</b>
@@ -335,7 +388,7 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan any, 5)
numbers := make(chan int, 5)
numbers <- 1
numbers <- 2
numbers <- 3
@@ -343,12 +396,16 @@ func main() {
numbers <- 5
defer close(numbers)
c := concurrency.NewChannel()
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, numbers, 3)
for val := range intStream {
fmt.Println(val) //1, 2, 3
for v := range intStream {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
}
```
@@ -356,12 +413,12 @@ func main() {
### <span id="Tee">Tee</span>
<p>Split one chanel into two channels until cancel context.</p>
<p>Split one chanel into two channels, until cancel the context.</p>
<b>Signature:</b>
```go
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
```
<b>Example:</b>
@@ -378,13 +435,19 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
out1, out2 := c.Tee(ctx, inStream)
for val := range out1 {
fmt.Println(val) //1
fmt.Println(<-out2) //1
ch1, ch2 := c.Tee(ctx, intStream)
for v := range ch1 {
fmt.Println(v)
fmt.Println(<-ch2)
}
// Output:
// 1
// 1
// 1
// 1
}
```
+128 -64
View File
@@ -43,8 +43,8 @@ import (
<b>函数签名:</b>
```go
type Channel struct {}
func NewChannel() *Channel
type Channel[T any] struct
func NewChannel[T any]() *Channel[T]
```
<b>例子:</b>
@@ -57,7 +57,7 @@ import (
)
func main() {
c := concurrency.NewChannel()
c := concurrency.NewChannel[int]()
}
```
@@ -65,12 +65,12 @@ func main() {
### <span id="Bridge">Bridge</span>
<p>将多个通道链接到一个通道,直到取消上下文。</p>
<p>将多个channel链接到一个channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Bridge(ctx context.Context, chanStream <-chan <-chan any) <-chan any
func (c *Channel[T]) Bridge(ctx context.Context, chanStream <-chan <-chan T) <-chan T
```
<b>例子:</b>
@@ -87,25 +87,30 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
genVals := func() <-chan <-chan any {
chanStream := make(chan (<-chan any))
c := concurrency.NewChannel[int]()
genVals := func() <-chan <-chan int {
out := make(chan (<-chan int))
go func() {
defer close(chanStream)
for i := 0; i < 10; i++ {
stream := make(chan any, 1)
defer close(out)
for i := 1; i <= 5; i++ {
stream := make(chan int, 1)
stream <- i
close(stream)
chanStream <- stream
out <- stream
}
}()
return chanStream
return out
}
index := 0
for val := range c.Bridge(ctx, genVals()) {
fmt.Printf("%v ", val) //0 1 2 3 4 5 6 7 8 9
for v := range c.Bridge(ctx, genVals()) {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
// 4
// 5
}
```
@@ -114,12 +119,12 @@ func main() {
### <span id="FanIn">FanIn</span>
<p>将多个通道合并为一个通道,直到取消上下文</p>
<p>将多个channel合并为一个channel,直到取消上下文</p>
<b>函数签名:</b>
```go
func (c *Channel) FanIn(ctx context.Context, channels ...<-chan any) <-chan any
func (c *Channel[T]) FanIn(ctx context.Context, channels ...<-chan T) <-chan T
```
<b>例子:</b>
@@ -136,30 +141,68 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
channels := make([]<-chan any, 3)
c := concurrency.NewChannel[int]()
channels := make([]<-chan int, 2)
for i := 0; i < 3; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 3)
for i := 0; i < 2; i++ {
channels[i] = c.Take(ctx, c.Repeat(ctx, i), 2)
}
mergedChannel := c.FanIn(ctx, channels...)
chs := c.FanIn(ctx, channels...)
for val := range mergedChannel {
fmt.Println("\t%d\n", val) //1,2,1,0,0,1,0,2,2 (order not for sure)
for v := range chs {
fmt.Println(v) //1 1 0 0 or 0 0 1 1
}
}
```
### <span id="Generate">Generate</span>
<p>根据传入的值,生成channel.</p>
<b>函数签名:</b>
```go
func (c *Channel[T]) Generate(ctx context.Context, values ...T) <-chan T
```
<b>例子:</b>
```go
package main
import (
"context"
"fmt"
"github.com/duke-git/lancet/v2/concurrency"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel[int]()
intStream := c.Generate(ctx, 1, 2, 3)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
fmt.Println(<-intStream)
// Output:
// 1
// 2
// 3
}
```
### <span id="Repeat">Repeat</span>
<p>返回一个chan,将参数`values`重复放入chan,直到取消上下文。</p>
<p>返回一个channel,将参数`values`重复放入channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Repeat(ctx context.Context, values ...any) <-chan any
func (c *Channel[T]) Repeat(ctx context.Context, values ...T) <-chan T
```
<b>例子:</b>
@@ -176,12 +219,17 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 5)
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
for v := range intStream {
fmt.Println(v) //1, 2, 1, 2, 1
fmt.Println(v)
}
// Output:
// 1
// 2
// 1
// 2
}
```
@@ -190,12 +238,12 @@ func main() {
### <span id="RepeatFn">RepeatFn</span>
<p>返回一个chan,重复执行函数fn,并将结果放入返回的chan,直到取消上下文。</p>
<p>返回一个channel,重复执行函数fn,并将结果放入返回的channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) RepeatFn(ctx context.Context, fn func() any) <-chan any
func (c *Channel[T]) RepeatFn(ctx context.Context, fn func() T) <-chan T
```
<b>例子:</b>
@@ -212,16 +260,20 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
fn := func() any {
s := "a"
return s
fn := func() string {
return "hello"
}
c := concurrency.NewChannel()
dataStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
for v := range dataStream {
fmt.Println(v) //a, a, a
c := concurrency.NewChannel[string]()
intStream := c.Take(ctx, c.RepeatFn(ctx, fn), 3)
for v := range intStream {
fmt.Println(v)
}
// Output:
// hello
// hello
// hello
}
```
@@ -229,12 +281,12 @@ func main() {
### <span id="Or">Or</span>
<p>将一个或多个通道读取到一个通道中,当任何读取通道关闭时将结束读取。</p>
<p>将一个或多个channel读取到一个channel中,当任何读取channel关闭时将结束读取。</p>
<b>函数签名:</b>
```go
func (c *Channel) Or(channels ...<-chan any) <-chan any
func (c *Channel[T]) Or(channels ...<-chan T) <-chan T
```
<b>例子:</b>
@@ -249,7 +301,7 @@ import (
func main() {
sig := func(after time.Duration) <-chan any {
c := make(chan interface{})
c := make(chan any)
go func() {
defer close(c)
time.Sleep(after)
@@ -259,13 +311,11 @@ func main() {
start := time.Now()
c := concurrency.NewChannel()
c := concurrency.NewChannel[any]()
<-c.Or(
sig(1*time.Second),
sig(2*time.Second),
sig(3*time.Second),
sig(4*time.Second),
sig(5*time.Second),
)
fmt.Println("done after %v", time.Since(start)) //1.003s
@@ -277,12 +327,12 @@ func main() {
### <span id="OrDone">OrDone</span>
<p>将一个通道读入另一个通道,直到取消上下文。</p>
<p>将一个channel读入另一个channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) OrDone(ctx context.Context, channel <-chan any) <-chan any
func (c *Channel[T]) OrDone(ctx context.Context, channel <-chan T) <-chan T
```
<b>例子:</b>
@@ -299,12 +349,16 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 3)
for val := range c.OrDone(ctx, intStream) {
fmt.Println(val) //1
for v := range c.OrDone(ctx, intStream) {
fmt.Println(v)
}
// Output:
// 1
// 1
// 1
}
```
@@ -313,12 +367,12 @@ func main() {
### <span id="Take">Take</span>
<p>返回一个chan,其值从另一个chan获取,直到取消上下文。</p>
<p>返回一个channel,其值从另一个channel获取,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Take(ctx context.Context, valueStream <-chan any, number int) <-chan any
func (c *Channel[T]) Take(ctx context.Context, valueStream <-chan T, number int) <-chan T
```
<b>例子:</b>
@@ -335,7 +389,7 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
numbers := make(chan any, 5)
numbers := make(chan int, 5)
numbers <- 1
numbers <- 2
numbers <- 3
@@ -343,12 +397,16 @@ func main() {
numbers <- 5
defer close(numbers)
c := concurrency.NewChannel()
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, numbers, 3)
for val := range intStream {
fmt.Println(val) //1, 2, 3
for v := range intStream {
fmt.Println(v)
}
// Output:
// 1
// 2
// 3
}
```
@@ -356,12 +414,12 @@ func main() {
### <span id="Tee">Tee</span>
<p>将一个通道分成两个通道,直到取消上下文。</p>
<p>将一个channel分成两个channel,直到取消上下文。</p>
<b>函数签名:</b>
```go
func (c *Channel) Tee(ctx context.Context, in <-chan any) (<-chan any, <-chan any)
func (c *Channel[T]) Tee(ctx context.Context, in <-chan T) (<-chan T, <-chan T)
```
<b>例子:</b>
@@ -378,13 +436,19 @@ func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
c := concurrency.NewChannel()
inStream := c.Take(ctx, c.Repeat(ctx, 1, 2), 4)
c := concurrency.NewChannel[int]()
intStream := c.Take(ctx, c.Repeat(ctx, 1), 2)
out1, out2 := c.Tee(ctx, inStream)
for val := range out1 {
fmt.Println(val) //1
fmt.Println(<-out2) //1
ch1, ch2 := c.Tee(ctx, intStream)
for v := range ch1 {
fmt.Println(v)
fmt.Println(<-ch2)
}
// Output:
// 1
// 1
// 1
// 1
}
```
+32 -5
View File
@@ -25,6 +25,7 @@ import (
- [Or](#Or)
- [Xor](#Generate)
- [Nor](#Nor)
- [Xnor](#Xnor)
- [Nand](#Nand)
- [TernaryOperator](#TernaryOperator)
@@ -120,7 +121,7 @@ func main() {
### <span id="Or">Or</span>
<p>Returns false iff neither a nor b is truthy.</p>
<p>Returns false if neither a nor b is truthy.</p>
<b>Signature:</b>
@@ -148,7 +149,7 @@ func main() {
### <span id="Xor">Xor</span>
<p>Returns true iff a or b but not both is truthy.</p>
<p>Returns true if a or b but not both is truthy.</p>
<b>Signature:</b>
@@ -176,7 +177,7 @@ func main() {
### <span id="Nor">Nor</span>
<p>Returns true iff neither a nor b is truthy.</p>
<p>Returns true if neither a nor b is truthy.</p>
<b>Signature:</b>
@@ -197,14 +198,40 @@ func main() {
fmt.Println(condition.Nor(0, 0)) // true
fmt.Println(condition.Nor(0, 1)) // false
fmt.Println(condition.Nor(1, 0)) // false
fmt.Println(condition.Nor(1, 1)) // true
fmt.Println(condition.Nor(1, 1)) // false
}
```
### <span id="Xnor">Xnor</span>
<p>Returns true if both a and b or neither a nor b are truthy.</p>
<b>Signature:</b>
```go
func Xnor[T, U any](a T, b U) bool
```
<b>Example:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Xnor(0, 0)) // true
fmt.Println(condition.Xnor(0, 1)) // false
fmt.Println(condition.Xnor(1, 0)) // false
fmt.Println(condition.Xnor(1, 1)) // true
}
```
### <span id="Nand">Nand</span>
<p>Returns false iff both a and b are truthy</p>
<p>Returns false if both a and b are truthy</p>
<b>Signature:</b>
+28 -1
View File
@@ -25,6 +25,7 @@ import (
- [Or](#Or)
- [Xor](#Generate)
- [Nor](#Nor)
- [Xnor](#Xnor)
- [Nand](#Nand)
- [TernaryOperator](#TernaryOperator)
@@ -196,12 +197,38 @@ func main() {
fmt.Println(condition.Nor(0, 0)) // true
fmt.Println(condition.Nor(0, 1)) // false
fmt.Println(condition.Nor(1, 0)) // false
fmt.Println(condition.Nor(1, 1)) // true
fmt.Println(condition.Nor(1, 1)) // false
}
```
### <span id="Xnor">Xnor</span>
<p>如果a和b都是真的或a和b均是假的,则返回true。</p>
<b>函数签名:</b>
```go
func Xnor[T, U any](a T, b U) bool
```
<b>例子:</b>
```go
package main
import (
"fmt"
"github.com/duke-git/lancet/v2/condition"
)
func main() {
fmt.Println(condition.Xnor(0, 0)) // true
fmt.Println(condition.Xnor(0, 1)) // false
fmt.Println(condition.Xnor(1, 0)) // false
fmt.Println(condition.Xnor(1, 1)) // true
}
```
### <span id="Nand">Nand</span>
<p>如果a和b都为真,返回false,否则返回true</p>
+6 -6
View File
@@ -102,7 +102,7 @@ func main() {
### <span id="ToBool">ToBool</span>
<p>Convert string to a boolean value. Use strconv.ParseBool</p>
<p>Convert string to bool. Use strconv.ParseBool.</p>
<b>Signature:</b>
@@ -138,7 +138,7 @@ func main() {
### <span id="ToBytes">ToBytes</span>
<p>Convert interface to byte slice.</p>
<p>Convert value to byte slice.</p>
<b>Signature:</b>
@@ -200,7 +200,7 @@ func main() {
### <span id="ToChannel">ToChannel</span>
<p>Convert a collection of elements to a read-only channels.</p>
<p>Convert a collection of elements to a read-only channel.</p>
<b>Signature:</b>
@@ -238,7 +238,7 @@ func main() {
### <span id="ToFloat">ToFloat</span>
<p>Convert interface to a float64 value. If param is a invalid floatable, will return 0 and error. </p>
<p>Convert value to a float64 value. If param is a invalid floatable, will return 0.0 and error. </p>
<b>Signature:</b>
@@ -271,7 +271,7 @@ func main() {
### <span id="ToInt">ToInt</span>
<p>Convert interface to a int64 value. If param is a invalid intable, will return 0 and error. </p>
<p>Convert value to a int64 value. If param is a invalid intable, will return 0 and error. </p>
<b>Signature:</b>
@@ -332,7 +332,7 @@ func main() {
### <span id="ToMap">ToMap</span>
<p>Convert a slice or an array of structs to a map based on iteratee function. </p>
<p>Convert a slice of structs to a map based on iteratee function. </p>
<b>Signature:</b>
+1 -1
View File
@@ -522,7 +522,7 @@ func main() {
### <span id="DecodeByte">DecodeByte</span>
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例</p>
<p>解码字节切片到目标对象,目标对象需要传入一个指针实例</p>
<b>函数签名:</b>
+3 -3
View File
@@ -5,10 +5,10 @@ Package cryptor contains some functions for data encryption and decryption. Supp
## Source:
- [https://github.com/duke-git/lancet/blob/main/cryptor/aes.go](https://github.com/duke-git/lancet/blob/main/cryptor/aes.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/des.go](https://github.com/duke-git/lancet/blob/main/cryptor/des.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/basic.go](https://github.com/duke-git/lancet/blob/main/cryptor/basic.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/rsa.go](https://github.com/duke-git/lancet/blob/main/cryptor/rsa.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/encrypt.go](https://github.com/duke-git/lancet/blob/main/cryptor/encrypt.go)
<div STYLE="page-break-after: always;"></div>
+2 -4
View File
@@ -5,10 +5,8 @@ cryptor加密包支持数据加密和解密,获取md5,hash值。支持base64
## 源码:
- [https://github.com/duke-git/lancet/blob/main/cryptor/aes.go](https://github.com/duke-git/lancet/blob/main/cryptor/aes.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/des.go](https://github.com/duke-git/lancet/blob/main/cryptor/des.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/basic.go](https://github.com/duke-git/lancet/blob/main/cryptor/basic.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/rsa.go](https://github.com/duke-git/lancet/blob/main/cryptor/rsa.go)
- [https://github.com/duke-git/lancet/blob/main/cryptor/encrypt.go](https://github.com/duke-git/lancet/blob/main/cryptor/encrypt.go)
<div STYLE="page-break-after: always;"></div>
@@ -186,7 +184,7 @@ func main() {
### <span id="AesCtrCrypt">AesCtrCrypt</span>
<p>使用AES CTR算法模式加密/解密数据. 参数`key`的长度是16, 24 or 32。</p>
<p>使用AES CTR算法模式加密/解密数据参数`key`的长度是16, 24 or 32。</p>
<b>函数签名:</b>
@@ -132,12 +132,12 @@ func main() {
### <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>
```go
func (link *SinglyLink[T]) InsertAt(index int, value T) error
func (link *SinglyLink[T]) InsertAt(index int, value T)
```
<b>Example:</b>
@@ -152,6 +152,8 @@ import (
func main() {
lk := link.NewSinglyLink[int]()
lk.InsertAt(1, 1) //do nothing
lk.InsertAt(0, 1)
lk.InsertAt(1, 2)
lk.InsertAt(2, 3)
@@ -228,12 +230,12 @@ func main() {
### <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>
```go
func (link *SinglyLink[T]) DeleteAt(index int) error
func (link *SinglyLink[T]) DeleteAt(index int)
```
<b>Example:</b>
@@ -253,9 +255,8 @@ func main() {
lk.InsertAtTail(3)
lk.InsertAtTail(4)
err := lk.DeleteAt(3)
lk.DeleteAt(3)
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{1, 2, 3}
}
```
@@ -268,7 +269,7 @@ func main() {
<b>Signature:</b>
```go
func (link *SinglyLink[T]) DeleteAtHead() error
func (link *SinglyLink[T]) DeleteAtHead()
```
<b>Example:</b>
@@ -288,9 +289,8 @@ func main() {
lk.InsertAtTail(3)
lk.InsertAtTail(4)
err := lk.DeleteAtHead()
lk.DeleteAtHead()
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{2, 3, 4}
}
```
@@ -304,7 +304,7 @@ func main() {
<b>Signature:</b>
```go
func (link *SinglyLink[T]) DeleteAtTail() error
func (link *SinglyLink[T]) DeleteAtTail()
```
<b>Example:</b>
@@ -323,9 +323,8 @@ func main() {
lk.InsertAtTail(2)
lk.InsertAtTail(3)
err := lk.DeleteAtTail()
lk.DeleteAtTail()
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{1, 2}
}
```
@@ -628,12 +627,12 @@ func main() {
### <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>
```go
func (link *DoublyLink[T]) InsertAt(index int, value T) error
func (link *DoublyLink[T]) InsertAt(index int, value T)
```
<b>Example:</b>
@@ -648,6 +647,8 @@ import (
func main() {
lk := link.NewDoublyLink[int]()
lk.InsertAt(1, 1) //do nothing
lk.InsertAt(0, 1)
lk.InsertAt(1, 2)
lk.InsertAt(2, 3)
@@ -724,12 +725,12 @@ func main() {
### <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>
```go
func (link *DoublyLink[T]) DeleteAt(index int) error
func (link *DoublyLink[T]) DeleteAt(index int)
```
<b>Example:</b>
@@ -749,9 +750,8 @@ func main() {
lk.InsertAtTail(3)
lk.InsertAtTail(4)
err := lk.DeleteAt(3)
lk.DeleteAt(3)
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{1, 2, 3}
}
```
@@ -764,7 +764,7 @@ func main() {
<b>Signature:</b>
```go
func (link *DoublyLink[T]) DeleteAtHead() error
func (link *DoublyLink[T]) DeleteAtHead()
```
<b>Example:</b>
@@ -784,9 +784,8 @@ func main() {
lk.InsertAtTail(3)
lk.InsertAtTail(4)
err := lk.DeleteAtHead()
lk.DeleteAtHead()
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{2, 3, 4}
}
```
@@ -137,7 +137,7 @@ func main() {
<b>函数签名:</b>
```go
func (link *SinglyLink[T]) InsertAt(index int, value T) error
func (link *SinglyLink[T]) InsertAt(index int, value T)
```
<b>例子:</b>
@@ -152,6 +152,8 @@ import (
func main() {
lk := link.NewSinglyLink[int]()
lk.InsertAt(1, 1) //do nothing
lk.InsertAt(0, 1)
lk.InsertAt(1, 2)
lk.InsertAt(2, 3)
@@ -233,7 +235,7 @@ func main() {
<b>函数签名:</b>
```go
func (link *SinglyLink[T]) DeleteAt(index int) error
func (link *SinglyLink[T]) DeleteAt(index int)
```
<b>例子:</b>
@@ -253,9 +255,8 @@ func main() {
lk.InsertAtTail(3)
lk.InsertAtTail(4)
err := lk.DeleteAt(3)
lk.DeleteAt(3)
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{1, 2, 3}
}
```
@@ -268,7 +269,7 @@ func main() {
<b>函数签名:</b>
```go
func (link *SinglyLink[T]) DeleteAtHead() error
func (link *SinglyLink[T]) DeleteAtHead()
```
<b>例子:</b>
@@ -288,9 +289,8 @@ func main() {
lk.InsertAtTail(3)
lk.InsertAtTail(4)
err := lk.DeleteAtHead()
lk.DeleteAtHead()
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{2, 3, 4}
}
```
@@ -304,7 +304,7 @@ func main() {
<b>函数签名:</b>
```go
func (link *SinglyLink[T]) DeleteAtTail() error
func (link *SinglyLink[T]) DeleteAtTail()
```
<b>例子:</b>
@@ -323,9 +323,8 @@ func main() {
lk.InsertAtTail(2)
lk.InsertAtTail(3)
err := lk.DeleteAtTail()
lk.DeleteAtTail()
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{1, 2}
}
```
@@ -633,7 +632,7 @@ func main() {
<b>函数签名:</b>
```go
func (link *DoublyLink[T]) InsertAt(index int, value T) error
func (link *DoublyLink[T]) InsertAt(index int, value T)
```
<b>例子:</b>
@@ -648,6 +647,8 @@ import (
func main() {
lk := link.NewDoublyLink[int]()
lk.InsertAt(1, 1) //do nothing
lk.InsertAt(0, 1)
lk.InsertAt(1, 2)
lk.InsertAt(2, 3)
@@ -729,7 +730,7 @@ func main() {
<b>函数签名:</b>
```go
func (link *DoublyLink[T]) DeleteAt(index int) error
func (link *DoublyLink[T]) DeleteAt(index int)
```
<b>例子:</b>
@@ -749,9 +750,8 @@ func main() {
lk.InsertAtTail(3)
lk.InsertAtTail(4)
err := lk.DeleteAt(3)
lk.DeleteAt(3)
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{1, 2, 3}
}
```
@@ -764,7 +764,7 @@ func main() {
<b>函数签名:</b>
```go
func (link *DoublyLink[T]) DeleteAtHead() error
func (link *DoublyLink[T]) DeleteAtHead()
```
<b>例子:</b>
@@ -784,9 +784,8 @@ func main() {
lk.InsertAtTail(3)
lk.InsertAtTail(4)
err := lk.DeleteAtHead()
lk.DeleteAtHead()
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{2, 3, 4}
}
```
@@ -800,7 +799,7 @@ func main() {
<b>函数签名:</b>
```go
func (link *DoublyLink[T]) DeleteAtTail() error
func (link *DoublyLink[T]) DeleteAtTail()
```
<b>例子:</b>
@@ -819,9 +818,8 @@ func main() {
lk.InsertAtTail(2)
lk.InsertAtTail(3)
err := lk.DeleteAtTail()
lk.DeleteAtTail()
fmt.Println(err) //nil
fmt.Println(lk.Values()) //[]int{1, 2}
}
```
+2 -2
View File
@@ -119,7 +119,7 @@ func main() {
### <span id="CopyFile">CopyFile</span>
<p>拷贝文件,会覆盖原有的拷贝文件</p>
<p>拷贝文件,会覆盖原有的文件</p>
<b>函数签名:</b>
@@ -261,7 +261,7 @@ func main() {
### <span id="IsDir">IsDir</span>
<p>判断目录是否存在</p>
<p>判断参数是否是目录</p>
<b>函数签名:</b>
+2 -3
View File
@@ -28,13 +28,12 @@ import (
### <span id="Comma">Comma</span>
<p>Add comma to number by every 3 numbers from right. ahead by symbol char.
Param should be number or numberic string.</p>
<p>Add comma to a number value by every 3 numbers from right to left. ahead by symbol char. if value is a invalid number string like "aa", return empty string.</p>
<b>Signature:</b>
```go
func Comma(v any, symbol string) string
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
```
<b>Example:</b>
+2 -2
View File
@@ -28,12 +28,12 @@ import (
### <span id="Comma">Comma</span>
<p>用逗号每隔3位分割数字/字符串,签名添加符号。参数必须是数字或者可以转为数字的字符串</p>
<p>用逗号每隔3位分割数字/字符串,支持前缀添加符号。参数value必须是数字或者可以转为数字的字符串, 否则返回空字符串</p>
<b>函数签名:</b>
```go
func Comma(v any, symbol string) string
func Comma[T constraints.Float | constraints.Integer | string](value T, symbol string) string
```
<b>例子:</b>
+27 -26
View File
@@ -22,7 +22,7 @@ import (
## Index
- [After](#After)
- [Before](#Before)
- [Curry](#Curry)
- [CurryFn](#CurryFn)
- [Compose](#Compose)
- [Debounced](#Debounced)
- [Delay](#Delay)
@@ -125,15 +125,15 @@ func main() {
### <span id="Curry">Curry</span>
### <span id="CurryFn">CurryFn</span>
<p>Make a curry function.</p>
<p>Make curry function.</p>
<b>Signature:</b>
```go
type Fn func(...any) any
func (f Fn) Curry(i any) func(...any) any
type CurryFn[T any] func(...T) T
func (cf CurryFn[T]) New(val T) func(...T) T
```
<b>Example:</b>
@@ -149,11 +149,14 @@ func main() {
add := func(a, b int) int {
return a + b
}
var addCurry function.Fn = func(values ...any) any {
return add(values[0].(int), values[1].(int))
var addCurry CurryFn[int] = func(values ...int) int {
return add(values[0], values[1])
}
add1 := addCurry.Curry(1)
add1 := addCurry.New(1)
result := add1(2)
fmt.Println(result) //3
}
```
@@ -167,7 +170,7 @@ func main() {
<b>Signature:</b>
```go
func Compose(fnList ...func(...any) any) func(...any) any
func Compose[T any](fnList ...func(...T) T) func(...T) T
```
<b>Example:</b>
@@ -180,17 +183,17 @@ import (
)
func main() {
add1 := func(v ...any) any {
return v[0].(int) + 1
toUpper := func(strs ...string) string {
return strings.ToUpper(strs[0])
}
add2 := func(v ...any) any {
return v[0].(int) + 2
toLower := func(strs ...string) string {
return strings.ToLower(strs[0])
}
transform := Compose(toUpper, toLower)
add3 := function.Compose(add1, add2)
result := add3(1)
result := transform("aBCde")
fmt.Println(result) //4
fmt.Println(result) //ABCDE
}
```
@@ -259,9 +262,9 @@ import (
func main() {
var print = func(s string) {
fmt.Println(count) //test delay
fmt.Println(count) //delay 2 seconds
}
function.Delay(2*time.Second, print, "test delay")
function.Delay(2*time.Second, print, "delay 2 seconds")
}
```
@@ -332,9 +335,9 @@ func main() {
return x * x
}
f := Pipeline(addOne, double, square)
fn := Pipeline(addOne, double, square)
fmt.Println(f(2)) //36
fmt.Println(fn(2)) //36
}
```
@@ -351,6 +354,7 @@ type Watcher struct {
stopTime int64
excuting bool
}
func NewWatcher() *Watcher
func (w *Watcher) Start() //start the watcher
func (w *Watcher) Stop() //stop the watcher
func (w *Watcher) Reset() //reset the watcher
@@ -367,7 +371,8 @@ import (
)
func main() {
w := &function.Watcher{}
w := function.NewWatcher()
w.Start()
longRunningTask()
@@ -377,14 +382,10 @@ func main() {
w.Stop()
eapsedTime := w.GetElapsedTime().Milliseconds()
fmt.Println(eapsedTime)
w.Reset()
fmt.Println(w.excuting) //false
fmt.Println(w.startTime) //0
fmt.Println(w.stopTime) //0
}
func longRunningTask() {
+24 -22
View File
@@ -22,7 +22,7 @@ import (
## 目录
- [After](#After)
- [Before](#Before)
- [Curry](#Curry)
- [CurryFn](#CurryFn)
- [Compose](#Compose)
- [Debounced](#Debounced)
- [Delay](#Delay)
@@ -124,15 +124,15 @@ func main() {
### <span id="Curry">Curry</span>
### <span id="CurryFn">CurryFn</span>
<p>创建一个柯里化函数</p>
<p>创建柯里化函数</p>
<b>函数签名:</b>
```go
type Fn func(...any) any
func (f Fn) Curry(i any) func(...any) any
type CurryFn[T any] func(...T) T
func (cf CurryFn[T]) New(val T) func(...T) T
```
<b>例子:</b>
@@ -148,11 +148,14 @@ func main() {
add := func(a, b int) int {
return a + b
}
var addCurry function.Fn = func(values ...any) any {
return add(values[0].(int), values[1].(int))
var addCurry CurryFn[int] = func(values ...int) int {
return add(values[0], values[1])
}
add1 := addCurry.Curry(1)
add1 := addCurry.New(1)
result := add1(2)
fmt.Println(result) //3
}
```
@@ -166,7 +169,7 @@ func main() {
<b>函数签名:</b>
```go
func Compose(fnList ...func(...any) any) func(...any) any
func Compose[T any](fnList ...func(...T) T) func(...T) T
```
<b>例子:</b>
@@ -179,17 +182,17 @@ import (
)
func main() {
add1 := func(v ...any) any {
return v[0].(int) + 1
toUpper := func(strs ...string) string {
return strings.ToUpper(strs[0])
}
add2 := func(v ...any) any {
return v[0].(int) + 2
toLower := func(strs ...string) string {
return strings.ToLower(strs[0])
}
transform := Compose(toUpper, toLower)
add3 := function.Compose(add1, add2)
result := add3(1)
result := transform("aBCde")
fmt.Println(result) //4
fmt.Println(result) //ABCDE
}
```
@@ -333,7 +336,7 @@ func main() {
f := Pipeline(addOne, double, square)
fmt.Println(f(2)) //36
fmt.Println(fn(2)) //36
}
```
@@ -351,6 +354,7 @@ type Watcher struct {
stopTime int64
excuting bool
}
func NewWatcher() *Watcher
func (w *Watcher) Start() //start the watcher
func (w *Watcher) Stop() //stop the watcher
func (w *Watcher) Reset() //reset the watcher
@@ -367,7 +371,8 @@ import (
)
func main() {
w := &function.Watcher{}
w := function.NewWatcher()
w.Start()
longRunningTask()
@@ -377,14 +382,11 @@ func main() {
w.Stop()
eapsedTime := w.GetElapsedTime().Milliseconds()
fmt.Println(eapsedTime)
w.Reset()
fmt.Println(w.excuting) //false
fmt.Println(w.startTime) //0
fmt.Println(w.stopTime) //0
}
func longRunningTask() {
+6 -6
View File
@@ -45,7 +45,7 @@ import (
<b>Signature:</b>
```go
func Average[T lancetconstraints.Number](numbers ...T) T
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>Example:</b>
@@ -157,7 +157,7 @@ func main() {
<b>Signature:</b>
```go
func Max[T lancetconstraints.Number](numbers ...T) T
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>Example:</b>
@@ -218,12 +218,12 @@ func main() {
### <span id="Min">Min</span>
<p>Return min value of numbers.</p>
<p>Return the minimum value of numbers.</p>
<b>Signature:</b>
```go
func Min[T lancetconstraints.Number](numbers ...T) T
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>Example:</b>
@@ -302,8 +302,8 @@ import (
)
func main() {
fmt.Println(mathutil.Percent(1, 2, 2)) //1
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
fmt.Println(mathutil.Percent(1, 2, 2)) //0.5
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //0.33
}
```
+5 -5
View File
@@ -44,7 +44,7 @@ import (
<b>函数签名:</b>
```go
func Average[T lancetconstraints.Number](numbers ...T) T
func Average[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>例子:</b>
@@ -154,7 +154,7 @@ func main() {
<b>函数签名:</b>
```go
func Max[T lancetconstraints.Number](numbers ...T) T
func Max[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>例子:</b>
@@ -220,7 +220,7 @@ func main() {
<b>函数签名:</b>
```go
func Min[T lancetconstraints.Number](numbers ...T) T
func Min[T constraints.Integer | constraints.Float](numbers ...T) T
```
<b>例子:</b>
@@ -299,8 +299,8 @@ import (
)
func main() {
fmt.Println(mathutil.Percent(1, 2, 2)) //1
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //33.33
fmt.Println(mathutil.Percent(1, 2, 2)) //0.5
fmt.Println(mathutil.Percent(0.1, 0.3, 2)) //0.33
}
```
+1 -1
View File
@@ -1138,7 +1138,7 @@ func main() {
<b>Signature:</b>
```go
func Sort[T lancetconstraints.Ordered](slice []T, sortOrder ...string)
func Sort[T constraints.Ordered](slice []T, sortOrder ...string)
```
<b>Example:</b>
+5 -5
View File
@@ -319,7 +319,7 @@ func main() {
### <span id="DifferenceBy">DifferenceBy</span>
<p>在slice和comparedSlice中的每个元素调用iteratee函数,并比较它们的返回值,如果不等返回在slice中对应的值</p>
<p>将两个slice中的每个元素调用iteratee函数,并比较它们的返回值,如果不等返回在slice中对应的值</p>
<b>函数签名:</b>
@@ -349,7 +349,7 @@ func main() {
### <span id="DifferenceWith">DifferenceWith</span>
<p>DifferenceWith 接受比较器,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定</p>
<p>接受比较器函数,该比较器被调用以将切片的元素与值进行比较。 结果值的顺序和引用由第一个切片确定</p>
<b>函数签名:</b>
@@ -379,7 +379,7 @@ func main() {
### <span id="DeleteAt">DeleteAt</span>
<p>删除切片中开始索引到结束索引-1的元素</p>
<p>删除切片中指定开始索引到结束索引的元素</p>
<b>函数签名:</b>
@@ -1135,7 +1135,7 @@ func main() {
<b>函数签名:</b>
```go
func Sort[T lancetconstraints.Ordered](slice []T, sortOrder ...string)
func Sort[T constraints.Ordered](slice []T, sortOrder ...string)
```
<b>例子:</b>
@@ -1442,7 +1442,7 @@ func main() {
### <span id="Union">Union</span>
<p>合并多个切片.</p>
<p>合并多个切片</p>
<b>函数签名:</b>
+152 -13
View File
@@ -28,13 +28,16 @@ import (
- [Capitalize](#Capitalize)
- [IsString](#IsString)
- [KebabCase](#KebabCase)
- [UpperKebabCase](#UpperKebabCase)
- [LowerFirst](#LowerFirst)
- [UpperFirst](#UpperFirst)
- [PadEnd](#PadEnd)
- [PadStart](#PadStart)
- [Reverse](#Reverse)
- [SnakeCase](#SnakeCase)
- [UpperSnakeCase](#UpperSnakeCase)
- [SplitEx](#SplitEx)
- [Substring](#Substring)
- [Wrap](#Wrap)
- [Unwrap](#Unwrap)
@@ -45,7 +48,7 @@ import (
### <span id="After">After</span>
<p>Creates substring in source string after position when char first appear.</p>
<p>Returns the substring after the first occurrence of a specified string in the source string.</p>
<b>Signature:</b>
@@ -75,7 +78,7 @@ func main() {
### <span id="AfterLast">AfterLast</span>
<p>Creates substring in source string after position when char last appear.</p>
<p>Returns the substring after the last occurrence of a specified string in the source string.</p>
<b>Signature:</b>
@@ -106,7 +109,7 @@ func main() {
### <span id="Before">Before</span>
<p>Creates substring in source string before position when char first appear.</p>
<p>Returns the substring of the source string up to the first occurrence of the specified string.</p>
<b>Signature:</b>
@@ -137,7 +140,7 @@ func main() {
### <span id="BeforeLast">BeforeLast</span>
<p>Creates substring in source string before position when char first appear.</p>
<p>Returns the substring of the source string up to the last occurrence of the specified string.</p>
<b>Signature:</b>
@@ -165,10 +168,8 @@ func main() {
```
### <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>
@@ -195,6 +196,75 @@ func main() {
s4 := strutil.CamelCase("foo bar")
fmt.Println(s4) //fooBar
s4 := strutil.CamelCase("Foo-#1😄$_%^&*(1bar")
fmt.Println(s4) //foo11Bar
}
```
### <span id="KebabCase">KebabCase</span>
<p>KebabCase covert string to kebab-case, non letters and numbers will be ignored.</p>
<b>Signature:</b>
```go
func KebabCase(s string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.KebabCase("Foo Bar-")
fmt.Println(s1) //foo-bar
s2 := strutil.KebabCase("foo_Bar")
fmt.Println(s2) //foo-bar
s3 := strutil.KebabCase("fooBar")
fmt.Println(s3) //foo-bar
s4 := strutil.KebabCase("__FOO_BAR__")
fmt.Println(s4) //foo-bar
}
```
### <span id="UpperKebabCase">UpperKebabCase</span>
<p>UpperKebabCase covert string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
<b>Signature:</b>
```go
func KebabCase(s string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.UpperKebabCase("Foo Bar-")
fmt.Println(s1) //FOO-BAR
s2 := strutil.UpperKebabCase("foo_Bar")
fmt.Println(s2) //FOO-BAR
s3 := strutil.UpperKebabCase("fooBar")
fmt.Println(s3) //FOO-BAR
s4 := strutil.UpperKebabCase("__FOO_BAR__")
fmt.Println(s4) //FOO-BAR
}
```
@@ -457,7 +527,7 @@ func main() {
### <span id="SnakeCase">SnakeCase</span>
<p>Covert string to snake_case.</p>
<p>Coverts string to snake_case, non letters and numbers will be ignored.</p>
<b>Signature:</b>
@@ -483,14 +553,47 @@ func main() {
fmt.Println(s3) //foo_bar
s4 := strutil.SnakeCase("__FOO_BAR__")
fmt.Println(s4) //f_o_o_b_a_r
fmt.Println(s4) //foo_bar
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
fmt.Println(s5) //a_bbc_s_a_b_b_c
s5 := strutil.SnakeCase("Foo-#1😄$_%^&*(1bar")
fmt.Println(s5) //foo_1_1_bar
}
```
### <span id="UpperSnakeCase">UpperSnakeCase</span>
<p>Coverts string to upper KEBAB-CASE, non letters and numbers will be ignored.</p>
<b>Signature:</b>
```go
func SnakeCase(s string) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.UpperSnakeCase("Foo Bar-")
fmt.Println(s1) //FOO_BAR
s2 := strutil.UpperSnakeCase("foo_Bar")
fmt.Println(s2) //FOO_BAR
s3 := strutil.UpperSnakeCase("fooBar")
fmt.Println(s3) //FOO_BAR
s4 := strutil.UpperSnakeCase("__FOO_BAR__")
fmt.Println(s4) //FOO_BAR
s5 := strutil.UpperSnakeCase("Foo-#1😄$_%^&*(1bar")
fmt.Println(s5) //FOO_1_1_BAR
}
```
### <span id="SplitEx">SplitEx</span>
@@ -529,9 +632,45 @@ func main() {
### <span id="Substring">Substring</span>
<p>Returns a substring of the specified length starting at the specified offset position.</p>
<b>Signature:</b>
```go
func Substring(s string, offset int, length uint) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.Substring("abcde", 1, 3)
fmt.Println(result1) //bcd
result2 := strutil.Substring("abcde", 1, 5)
fmt.Println(result2) //bcde
result3 := strutil.Substring("abcde", -1, 3)
fmt.Println(result3) //e
result4 := strutil.Substring("abcde", -2, 2)
fmt.Println(result4) //de
result5 := strutil.Substring("abcde", -2, 3)
fmt.Println(result5) //de
result6 := strutil.Substring("你好,欢迎你", 0, 2)
fmt.Println(result6) //你好
}
```
### <span id="Wrap">Wrap</span>
<p>Wrap a string with another string.</p>
<p>Wrap a string with given string.</p>
<b>Signature:</b>
@@ -568,7 +707,7 @@ func main() {
### <span id="Wrap">Wrap</span>
<p>Unwrap a given string from anther string. will change str value.</p>
<p>Unwrap a given string from anther string. will change source string.</p>
<b>Signature:</b>
+123 -13
View File
@@ -28,13 +28,16 @@ import (
- [Capitalize](#Capitalize)
- [IsString](#IsString)
- [KebabCase](#KebabCase)
- [UpperKebabCase](#UpperKebabCase)
- [LowerFirst](#LowerFirst)
- [UpperFirst](#UpperFirst)
- [PadEnd](#PadEnd)
- [PadStart](#PadStart)
- [Reverse](#Reverse)
- [SnakeCase](#SnakeCase)
- [UpperSnakeCase](#UpperSnakeCase)
- [SplitEx](#SplitEx)
- [Substring](#Substring)
- [Wrap](#Wrap)
- [Unwrap](#Unwrap)
@@ -46,7 +49,7 @@ import (
### <span id="After">After</span>
<p>截取源字符串中char首次出现时的位置之后的子字符串</p>
<p>返回源字符串中特定字符串首次出现时的位置之后的子字符串</p>
<b>函数签名:</b>
@@ -76,7 +79,7 @@ func main() {
### <span id="AfterLast">AfterLast</span>
<p>截取源字符串中char最后一次出现时的位置之后的子字符串</p>
<p>返回源字符串中指定字符串最后一次出现时的位置之后的子字符串</p>
<b>函数签名:</b>
@@ -107,7 +110,7 @@ func main() {
### <span id="Before">Before</span>
<p>截取源字符串中char首次出现时的位置之前的子字符串</p>
<p>返回源字符串中指定字符串第一次出现时的位置之前的子字符串</p>
<b>函数签名:</b>
@@ -138,7 +141,7 @@ func main() {
### <span id="BeforeLast">BeforeLast</span>
<p>截取源字符串中char最后一次出现时的位置之前的子字符串</p>
<p>返回源字符串中指定字符串最后一次出现时的位置之前的子字符串</p>
<b>函数签名:</b>
@@ -169,7 +172,7 @@ func main() {
### <span id="CamelCase">CamelCase</span>
<p>将字符串转换为驼峰式字符串</p>
<p>将字符串转换为驼峰式字符串, 非字母和数字会被忽略</p>
<b>函数签名:</b>
@@ -196,6 +199,9 @@ func main() {
s4 := strutil.CamelCase("foo bar")
fmt.Println(s4) //fooBar
s4 := strutil.CamelCase("Foo-#1😄$_%^&*(1bar")
fmt.Println(s4) //foo11Bar
}
```
@@ -233,7 +239,7 @@ func main() {
### <span id="IsString">IsString</span>
<p>检查值的数据类型是否为字符串</p>
<p>判断传入参数的数据类型是否为字符串</p>
<b>函数签名:</b>
@@ -261,7 +267,7 @@ func main() {
### <span id="KebabCase">KebabCase</span>
<p>将字符串转换为kebab-case</p>
<p>将字符串转换为kebab-case, 非字母和数字会被忽略</p>
<b>函数签名:</b>
@@ -287,7 +293,40 @@ func main() {
fmt.Println(s3) //foo-bar
s4 := strutil.KebabCase("__FOO_BAR__")
fmt.Println(s4) //f-o-o-b-a-r
fmt.Println(s4) //foo-bar
}
```
### <span id="UpperKebabCase">UpperKebabCase</span>
<p>将字符串转换为大写KEBAB-CASE, 非字母和数字会被忽略</p>
<b>函数签名:</b>
```go
func KebabCase(s string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.UpperKebabCase("Foo Bar-")
fmt.Println(s1) //FOO-BAR
s2 := strutil.UpperKebabCase("foo_Bar")
fmt.Println(s2) //FOO-BAR
s3 := strutil.UpperKebabCase("fooBar")
fmt.Println(s3) //FOO-BAR
s4 := strutil.UpperKebabCase("__FOO_BAR__")
fmt.Println(s4) //FOO-BAR
}
```
@@ -329,7 +368,7 @@ func main() {
### <span id="UpperFirst">UpperFirst</span>
<p>将字符串的第一个字符转换为大写</p>
<p>将字符串的第一个字符转换为大写形式</p>
<b>函数签名:</b>
@@ -458,7 +497,7 @@ func main() {
### <span id="SnakeCase">SnakeCase</span>
<p>将字符串转换为snake_case形式</p>
<p>将字符串转换为snake_case形式, 非字母和数字会被忽略</p>
<b>函数签名:</b>
@@ -484,10 +523,45 @@ func main() {
fmt.Println(s3) //foo_bar
s4 := strutil.SnakeCase("__FOO_BAR__")
fmt.Println(s4) //f_o_o_b_a_r
fmt.Println(s4) //foo_bar
s5 := strutil.SnakeCase("aBbc-s$@a&%_B.B^C")
fmt.Println(s5) //a_bbc_s_a_b_b_c
s5 := strutil.SnakeCase("Foo-#1😄$_%^&*(1bar")
fmt.Println(s5) //foo_1_1_bar
}
```
### <span id="UpperSnakeCase">UpperSnakeCase</span>
<p>将字符串转换为大写SNAKE_CASE形式, 非字母和数字会被忽略</p>
<b>函数签名:</b>
```go
func SnakeCase(s string) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
s1 := strutil.UpperSnakeCase("Foo Bar-")
fmt.Println(s1) //FOO_BAR
s2 := strutil.UpperSnakeCase("foo_Bar")
fmt.Println(s2) //FOO_BAR
s3 := strutil.UpperSnakeCase("fooBar")
fmt.Println(s3) //FOO_BAR
s4 := strutil.UpperSnakeCase("__FOO_BAR__")
fmt.Println(s4) //FOO_BAR
s5 := strutil.UpperSnakeCase("Foo-#1😄$_%^&*(1bar")
fmt.Println(s5) //FOO_1_1_BAR
}
```
@@ -527,6 +601,42 @@ func main() {
}
```
### <span id="Substring">Substring</span>
<p>根据指定的位置和长度截取子字符串</p>
<b>函数签名:</b>
```go
func Substring(s string, offset int, length uint) string
```
<b>例子:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.Substring("abcde", 1, 3)
fmt.Println(result1) //bcd
result2 := strutil.Substring("abcde", 1, 5)
fmt.Println(result2) //bcde
result3 := strutil.Substring("abcde", -1, 3)
fmt.Println(result3) //e
result4 := strutil.Substring("abcde", -2, 2)
fmt.Println(result4) //de
result5 := strutil.Substring("abcde", -2, 3)
fmt.Println(result5) //de
result6 := strutil.Substring("你好,欢迎你", 0, 2)
fmt.Println(result6) //你好
}
```
### <span id="Wrap">Wrap</span>
+20 -6
View File
@@ -102,7 +102,7 @@ import (
)
func main() {
isOsMac := system.IsMac
isOsMac := system.IsMac()
fmt.Println(isOsMac)
}
```
@@ -211,7 +211,7 @@ func main() {
### <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>
@@ -227,10 +227,24 @@ import (
)
func main() {
out, errout, err := system.ExecCommand("ls")
fmt.Println(out)
fmt.Println(errout)
fmt.Println(err)
// linux or mac
stdout, stderr, err := system.ExecCommand("ls")
fmt.Println("std out: ", stdout)
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)
- [SetOsEnv](#SetOsEnv)
- [RemoveOsEnv](#RemoveOsEnv)
- [CompareOsEnv](#CompareOsEnv)
- [ExecCommand](#ExecCommand)
- [GetOsBits](#GetOsBits)
@@ -103,7 +102,7 @@ import (
)
func main() {
isOsMac := system.IsMac
isOsMac := system.IsMac()
fmt.Println(isOsMac)
}
```
@@ -212,7 +211,7 @@ func main() {
### <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>
@@ -228,10 +227,24 @@ import (
)
func main() {
out, errout, err := system.ExecCommand("ls")
fmt.Println(out)
fmt.Println(errout)
fmt.Println(err)
// linux or mac
stdout, stderr, err := system.ExecCommand("ls")
fmt.Println("std out: ", stdout)
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)
- [IsWeakPassword](#IsWeakPassword)
- [IsZeroValue](#IsZeroValue)
- [IsGBK](#IsGBK)
<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)
- [IsWeakPassword](#IsWeakPassword)
- [IsZeroValue](#IsZeroValue)
- [IsGBK](#IsGBK)
<div STYLE="page-break-after: always;"></div>
@@ -458,8 +459,6 @@ func main() {
### <span id="IsEmptyString">IsEmptyString</span>
<p>验证字符串是否是空字符串</p>
@@ -487,7 +486,6 @@ func main() {
### <span id="IsFloatStr">IsFloatStr</span>
<p>验证字符串是否是可以转换为浮点数</p>
@@ -573,8 +571,6 @@ func main() {
```
### <span id="IsRegexMatch">IsRegexMatch</span>
<p>验证字符串是否可以匹配正则表达式</p>
@@ -600,7 +596,6 @@ func main() {
### <span id="IsIntStr">IsIntStr</span>
<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")
}
```
+47 -22
View File
@@ -11,7 +11,6 @@ import (
"fmt"
"io"
"io/fs"
"io/ioutil"
"net/http"
"os"
"path"
@@ -19,7 +18,8 @@ import (
"strings"
)
// IsExist checks if a file or directory exists
// IsExist checks if a file or directory exists.
// Play: https://go.dev/play/p/nKKXt8ZQbmh
func IsExist(path string) bool {
_, err := os.Stat(path)
if err == nil {
@@ -31,7 +31,8 @@ func IsExist(path string) bool {
return false
}
// CreateFile create a file in path
// CreateFile create a file in path.
// Play: https://go.dev/play/p/lDt8PEsTNKI
func CreateFile(path string) bool {
file, err := os.Create(path)
if err != nil {
@@ -42,12 +43,14 @@ func CreateFile(path string) bool {
return true
}
// CreateDir create directory in absolute path. param `absPath` like /a/, /a/b/
// CreateDir create directory in absolute path. param `absPath` like /a/, /a/b/.
// Play: https://go.dev/play/p/qUuCe1OGQnM
func CreateDir(absPath string) error {
return os.MkdirAll(path.Dir(absPath), os.ModePerm)
}
// IsDir checks if the path is directory or not
// IsDir checks if the path is directory or not.
// Play: https://go.dev/play/p/WkVwEKqtOWk
func IsDir(path string) bool {
file, err := os.Stat(path)
if err != nil {
@@ -56,12 +59,14 @@ func IsDir(path string) bool {
return file.IsDir()
}
// RemoveFile remove the path file
// RemoveFile remove the path file.
// Play: https://go.dev/play/p/P2y0XW8a1SH
func RemoveFile(path string) error {
return os.Remove(path)
}
// CopyFile copy src file to dest file
// CopyFile copy src file to dest file.
// Play: https://go.dev/play/p/Jg9AMJMLrJi
func CopyFile(srcFilePath string, dstFilePath string) error {
srcFile, err := os.Open(srcFilePath)
if err != nil {
@@ -78,17 +83,21 @@ func CopyFile(srcFilePath string, dstFilePath string) error {
var tmp = make([]byte, 1024*4)
for {
n, err := srcFile.Read(tmp)
distFile.Write(tmp[:n])
if err != nil {
if err == io.EOF {
return nil
}
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 {
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
if err != nil {
@@ -100,16 +109,18 @@ func ClearFile(path string) error {
return err
}
//ReadFileToString return string of file content
// ReadFileToString return string of file content.
// Play: https://go.dev/play/p/cmfwp_5SQTp
func ReadFileToString(path string) (string, error) {
bytes, err := ioutil.ReadFile(path)
bytes, err := os.ReadFile(path)
if err != nil {
return "", err
}
return string(bytes), nil
}
// ReadFileByLine read file line by line
// ReadFileByLine read file line by line.
// Play: https://go.dev/play/p/svJP_7ZrBrD
func ReadFileByLine(path string) ([]string, error) {
f, err := os.Open(path)
if err != nil {
@@ -135,13 +146,14 @@ func ReadFileByLine(path string) ([]string, error) {
return result, nil
}
// ListFileNames return all file names in the path
// ListFileNames return all file names in the path.
// Play: https://go.dev/play/p/Tjd7Y07rejl
func ListFileNames(path string) ([]string, error) {
if !IsExist(path) {
return []string{}, nil
}
fs, err := ioutil.ReadDir(path)
fs, err := os.ReadDir(path)
if err != nil {
return []string{}, err
}
@@ -161,7 +173,8 @@ func ListFileNames(path string) ([]string, error) {
return result, nil
}
// Zip create zip file, fpath could be a single file or a directory
// Zip create zip file, fpath could be a single file or a directory.
// Play: https://go.dev/play/p/j-3sWBp8ik_P
func Zip(fpath string, destPath string) error {
zipFile, err := os.Create(destPath)
if err != nil {
@@ -172,7 +185,7 @@ func Zip(fpath string, destPath string) error {
archive := zip.NewWriter(zipFile)
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 {
return err
}
@@ -209,10 +222,15 @@ func Zip(fpath string, destPath string) error {
return nil
})
if err != nil {
return err
}
return nil
}
// UnZip unzip the file and save it to destPath
// UnZip unzip the file and save it to destPath.
// Play: https://go.dev/play/p/g0w34kS7B8m
func UnZip(zipFile string, destPath string) error {
zipReader, err := zip.OpenReader(zipFile)
@@ -229,9 +247,13 @@ func UnZip(zipFile string, destPath string) error {
}
if f.FileInfo().IsDir() {
os.MkdirAll(path, os.ModePerm)
err = os.MkdirAll(path, os.ModePerm)
if err != nil {
return err
}
} 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
}
@@ -267,7 +289,8 @@ func safeFilepathJoin(path1, path2 string) (string, error) {
return filepath.Join(path1, filepath.Join("/", relPath)), nil
}
// IsLink checks if a file is symbol link or not
// IsLink checks if a file is symbol link or not.
// Play: https://go.dev/play/p/TL-b-Kzvf44
func IsLink(path string) bool {
fi, err := os.Lstat(path)
if err != nil {
@@ -276,7 +299,8 @@ func IsLink(path string) bool {
return fi.Mode()&os.ModeSymlink != 0
}
// FileMode return file's mode and permission
// FileMode return file's mode and permission.
// Play: https://go.dev/play/p/2l2hI42fA3p
func FileMode(path string) (fs.FileMode, error) {
fi, err := os.Lstat(path)
if err != nil {
@@ -286,7 +310,8 @@ func FileMode(path string) (fs.FileMode, error) {
}
// MiMeType return file mime type
// param `file` should be string(file path) or *os.File
// param `file` should be string(file path) or *os.File.
// Play: https://go.dev/play/p/bd5sevSUZNu
func MiMeType(file any) string {
var mediatype string
+225
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 := "./test.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("./")
fmt.Println(fileList)
// Output:
// [file.go file_example_test.go file_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
}
+24 -7
View File
@@ -25,9 +25,10 @@ func TestCreateFile(t *testing.T) {
f := "./text.txt"
if CreateFile(f) {
file, err := os.Open(f)
defer file.Close()
assert.IsNil(err)
assert.Equal(f, file.Name())
defer file.Close()
} else {
t.FailNow()
}
@@ -113,7 +114,11 @@ func TestReadFileToString(t *testing.T) {
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello world")
_, err := f.WriteString("hello world")
if err != nil {
t.Log(err)
}
content, _ := ReadFileToString(path)
assert.Equal("hello world", content)
@@ -130,9 +135,12 @@ func TestClearFile(t *testing.T) {
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
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)
content, _ := ReadFileToString(path)
@@ -148,8 +156,13 @@ func TestReadFileByLine(t *testing.T) {
CreateFile(path)
f, _ := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
defer f.Close()
f.WriteString("hello\nworld")
_, err := f.WriteString("hello\nworld")
if err != nil {
t.Log(err)
}
expected := []string{"hello", "world"}
actual, _ := ReadFileByLine(path)
@@ -166,10 +179,14 @@ func TestZipAndUnZip(t *testing.T) {
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, 0777)
defer file.Close()
file.WriteString("hello\nworld")
_, err := file.WriteString("hello\nworld")
if err != nil {
t.Fail()
}
zipFile := "./text.zip"
err := Zip(srcFile, zipFile)
err = Zip(srcFile, zipFile)
assert.IsNil(err)
unZipPath := "./unzip"
+58 -4
View File
@@ -4,14 +4,68 @@
// Package formatter implements some functions to format string, struct.
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, ".")
if dotIndex != -1 {
return symbol + commaString(s[:dotIndex]) + s[dotIndex:]
}
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("aa", ""))
assert.Equal("", Comma("aa.a", ""))
assert.Equal("", Comma([]int{1}, ""))
assert.Equal("123", Comma("123", ""))
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.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, ""))
}
+56 -22
View File
@@ -5,11 +5,13 @@
package function
import (
"fmt"
"reflect"
"time"
)
// After creates a function that invokes func once it's called n or more times
// After creates a function that invokes func once it's called n or more times.
// Play: https://go.dev/play/p/8mQhkFmsgqs
func After(n int, fn any) func(args ...any) []reflect.Value {
// Catch programming error while constructing the closure
mustBeFunction(fn)
@@ -23,7 +25,8 @@ func After(n int, fn any) func(args ...any) []reflect.Value {
}
}
// Before creates a function that invokes func once it's called less than n times
// Before creates a function that invokes func once it's called less than n times.
// Play: https://go.dev/play/p/0HqUDIFZ3IL
func Before(n int, fn any) func(args ...any) []reflect.Value {
// Catch programming error while constructing the closure
mustBeFunction(fn)
@@ -40,41 +43,48 @@ func Before(n int, fn any) func(args ...any) []reflect.Value {
}
}
// Fn is for curry function which is func(...any) any
type Fn func(...any) any
// CurryFn is for make curry function
type CurryFn[T any] func(...T) T
// Curry make a curry function
func (f Fn) Curry(i any) func(...any) any {
return func(values ...any) any {
v := append([]any{i}, values...)
return f(v...)
// New make a curry function for specific value.
// Play: Todo
func (cf CurryFn[T]) New(val T) func(...T) T {
return func(vals ...T) T {
args := append([]T{val}, vals...)
return cf(args...)
}
}
// Compose compose the functions from right to left
func Compose(fnList ...func(...any) any) func(...any) any {
return func(s ...any) any {
f := fnList[0]
restFn := fnList[1:]
// Compose compose the functions from right to left.
// Play: Todo
func Compose[T any](fnList ...func(...T) T) func(...T) T {
return func(args ...T) T {
firstFn := fnList[0]
restFns := fnList[1:]
if len(fnList) == 1 {
return f(s...)
return firstFn(args...)
}
return f(Compose(restFn...)(s...))
fn := Compose(restFns...)
arg := fn(args...)
return firstFn(arg)
}
}
// Delay make the function execution after delayed time
// Delay make the function execution after delayed time.
// Play: https://go.dev/play/p/Ivtc2ZE-Tye
func Delay(delay time.Duration, fn any, args ...any) {
// Catch programming error while constructing the closure
mustBeFunction(fn)
time.Sleep(delay)
invokeFunc(fn, args...)
unsafeInvokeFunc(fn, args...)
}
// Debounced creates a debounced function that delays invoking fn until after wait duration have elapsed since the last time the debounced function was invoked.
// Play: https://go.dev/play/p/absuEGB_GN7
func Debounced(fn func(), duration time.Duration) func() {
// Catch programming error while constructing the closure
mustBeFunction(fn)
@@ -84,17 +94,16 @@ func Debounced(fn func(), duration time.Duration) func() {
go func() {
for {
select {
case <-timer.C:
<-timer.C
go fn()
}
}
}()
return func() { timer.Reset(duration) }
}
// Schedule invoke function every duration time, util close the returned bool chan
// Schedule invoke function every duration time, util close the returned bool channel.
// Play: https://go.dev/play/p/hbON-Xeyn5N
func Schedule(d time.Duration, fn any, args ...any) chan bool {
// Catch programming error while constructing the closure
mustBeFunction(fn)
@@ -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
// the functions one by one.
// Play: https://go.dev/play/p/mPdUVvj6HD6
func Pipeline[T any](funcs ...func(T) T) func(T) T {
return func(arg T) (result T) {
result = arg
@@ -125,3 +135,27 @@ func Pipeline[T any](funcs ...func(T) T) func(T) T {
return
}
}
func unsafeInvokeFunc(fn any, args ...any) []reflect.Value {
fv := reflect.ValueOf(fn)
params := make([]reflect.Value, len(args))
for i, item := range args {
params[i] = reflect.ValueOf(item)
}
return fv.Call(params)
}
func 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))
}
}
+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() {
var result []string
appendFn := func(s string) {
result = append(result, s)
}
stop := Schedule(1*time.Second, appendFn, "*")
time.Sleep(3 * time.Second)
close(stop)
fmt.Println(result)
// Output:
// [* * *]
}
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 {
return a + b
}
var addCurry Fn = func(values ...any) any {
return add(values[0].(int), values[1].(int))
var addCurry CurryFn[int] = func(values ...int) int {
return add(values[0], values[1])
}
add1 := addCurry.Curry(1)
add1 := addCurry.New(1)
assert.Equal(3, add1(2))
}
func TestCompose(t *testing.T) {
assert := internal.NewAssert(t, "TestCompose")
toUpper := func(a ...any) any {
return strings.ToUpper(a[0].(string))
toUpper := func(strs ...string) string {
return strings.ToUpper(strs[0])
}
toLower := func(a ...any) any {
return strings.ToLower(a[0].(string))
toLower := func(strs ...string) string {
return strings.ToLower(strs[0])
}
expected := toUpper(toLower("aBCde"))
cf := Compose(toUpper, toLower)
res := cf("aBCde")
+6
View File
@@ -3,12 +3,18 @@ package function
import "time"
// Watcher is used for record code excution time
// Play: Todo
type Watcher struct {
startTime int64
stopTime int64
excuting bool
}
// Start the watch timer.
func NewWatcher() *Watcher {
return &Watcher{}
}
// Start the watch timer.
func (w *Watcher) Start() {
w.startTime = time.Now().UnixNano()
+22
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) {
assert := internal.NewAssert(t, "TestWatcher")
w := &Watcher{}
w := NewWatcher()
w.Start()
longRunningTask()
+5
View File
@@ -1,3 +1,8 @@
module github.com/duke-git/lancet/v2
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.
// 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.
// 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 "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`.
type Iterator[T any] interface {
@@ -100,21 +104,15 @@ func (iter *sliceIterator[T]) HasNext() bool {
func (iter *sliceIterator[T]) Next() (T, bool) {
iter.index++
ok := iter.index >= 0 && iter.index < len(iter.slice)
var item T
if ok {
item = iter.slice[iter.index]
}
return item, ok
// if len(iter.slice) == 0 {
// var zero T
// return zero, false
// }
// iter.index++
// item := iter.slice[0]
// iter.slice = iter.slice[1:]
// return item, true
return item, ok
}
// Prev implements PrevIterator.
@@ -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
// 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 {
panic("RangeIterator: start should be before end")
} 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}
}
type rangeIterator[T lancetconstraints.Number] struct {
type rangeIterator[T constraints.Integer | constraints.Float] struct {
start, end, step T
}
func (iter *rangeIterator[T]) HasNext() bool {
if iter.start >= iter.end {
return false
}
return true
return iter.start < iter.end
}
func (iter *rangeIterator[T]) Next() (T, bool) {
@@ -172,3 +167,41 @@ func (iter *rangeIterator[T]) Next() (T, bool) {
iter.start += iter.step
return num, true
}
// FromRange creates a iterator which returns the numeric range between start inclusive and end
// exclusive by the step size. start should be less than end, step shoud be positive.
func FromChannel[T any](channel <-chan T) Iterator[T] {
return &channelIterator[T]{channel: channel}
}
type channelIterator[T any] struct {
channel <-chan T
}
func (iter *channelIterator[T]) Next() (T, bool) {
item, ok := <-iter.channel
return item, ok
}
func (iter *channelIterator[T]) HasNext() bool {
return len(iter.channel) == 0
}
// ToChannel create a new goroutine to pull items from the channel iterator to the returned channel.
func ToChannel[T any](ctx context.Context, iter Iterator[T], buffer int) <-chan T {
result := make(chan T, buffer)
go func() {
defer close(result)
for item, ok := iter.Next(); ok; item, ok = iter.Next() {
select {
case result <- item:
case <-ctx.Done():
return
}
}
}()
return result
}
+53
View File
@@ -5,6 +5,7 @@
package iterator
import (
"context"
"testing"
"github.com/duke-git/lancet/v2/internal"
@@ -47,4 +48,56 @@ func TestSliceIterator(t *testing.T) {
assert.Equal(false, ok)
})
t.Run("slice iterator ToSlice: ", func(t *testing.T) {
iter := FromSlice([]int{1, 2, 3, 4})
item, _ := iter.Next()
assert.Equal(1, item)
data := ToSlice(iter)
assert.Equal([]int{2, 3, 4}, data)
})
}
func TestRangeIterator(t *testing.T) {
assert := internal.NewAssert(t, "TestRangeIterator")
t.Run("range iterator: ", func(t *testing.T) {
iter := FromRange(1, 4, 1)
item, ok := iter.Next()
assert.Equal(1, item)
assert.Equal(true, ok)
item, ok = iter.Next()
assert.Equal(2, item)
assert.Equal(true, ok)
item, ok = iter.Next()
assert.Equal(3, item)
assert.Equal(true, ok)
_, ok = iter.Next()
assert.Equal(false, ok)
assert.Equal(false, iter.HasNext())
})
}
func TestChannelIterator(t *testing.T) {
assert := internal.NewAssert(t, "TestRangeIterator")
iter := FromSlice([]int{1, 2, 3, 4})
ctx, cancel := context.WithCancel(context.Background())
iter = FromChannel(ToChannel(ctx, iter, 0))
item, ok := iter.Next()
assert.Equal(1, item)
assert.Equal(true, ok)
assert.Equal(true, iter.HasNext())
cancel()
_, ok = iter.Next()
assert.Equal(false, ok)
}
+79 -1
View File
@@ -3,7 +3,7 @@
// Package iterator provides a way to iterate over values stored in containers.
// 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.
// 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.
@@ -59,3 +59,81 @@ func (fr *filterIterator[T]) Next() (T, bool) {
func (fr *filterIterator[T]) HasNext() bool {
return fr.iter.HasNext()
}
// Join creates an iterator that join all elements of iters[0], then all elements of iters[1] and so on.
func Join[T any](iters ...Iterator[T]) Iterator[T] {
return &joinIterator[T]{
iters: iters,
}
}
type joinIterator[T any] struct {
iters []Iterator[T]
}
func (iter *joinIterator[T]) Next() (T, bool) {
for len(iter.iters) > 0 {
item, ok := iter.iters[0].Next()
if ok {
return item, true
}
iter.iters = iter.iters[1:]
}
var zero T
return zero, false
}
func (iter *joinIterator[T]) HasNext() bool {
if len(iter.iters) == 0 {
return false
}
if len(iter.iters) == 1 {
return iter.iters[0].HasNext()
}
result := iter.iters[0].HasNext()
for i := 1; i < len(iter.iters); i++ {
it := iter.iters[i]
hasNext := it.HasNext()
result = result || hasNext
}
return result
}
// Reduce reduces iter to a single value using the reduction function reducer
func Reduce[T any, U any](iter Iterator[T], initial U, reducer func(U, T) U) U {
acc := initial
for item, ok := iter.Next(); ok; item, ok = iter.Next() {
acc = reducer(acc, item)
}
return acc
}
func Take[T any](it Iterator[T], num int) Iterator[T] {
return &takeIterator[T]{it: it, num: num}
}
type takeIterator[T any] struct {
it Iterator[T]
num int
}
func (iter *takeIterator[T]) Next() (T, bool) {
if iter.num <= 0 {
var zero T
return zero, false
}
item, ok := iter.it.Next()
if ok {
iter.num--
}
return item, ok
}
func (iter *takeIterator[T]) HasNext() bool {
return iter.num > 0
}
+73
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
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
}
+17 -9
View File
@@ -6,7 +6,8 @@ package maputil
import "reflect"
// Keys returns a slice of the map's keys
// Keys returns a slice of the map's keys.
// Play: https://go.dev/play/p/xNB5bTb97Wd
func Keys[K comparable, V any](m map[K]V) []K {
keys := make([]K, len(m))
@@ -19,7 +20,8 @@ func Keys[K comparable, V any](m map[K]V) []K {
return keys
}
// Values returns a slice of the map's values
// Values returns a slice of the map's values.
// Play: https://go.dev/play/p/CBKdUc5FTW6
func Values[K comparable, V any](m map[K]V) []V {
values := make([]V, len(m))
@@ -32,7 +34,8 @@ func Values[K comparable, V any](m map[K]V) []V {
return values
}
// Merge maps, next key will overwrite previous key
// Merge maps, next key will overwrite previous key.
// Play: https://go.dev/play/p/H95LENF1uB-
func Merge[K comparable, V any](maps ...map[K]V) map[K]V {
result := make(map[K]V, 0)
@@ -45,14 +48,16 @@ func Merge[K comparable, V any](maps ...map[K]V) map[K]V {
return result
}
// ForEach executes iteratee funcation for every key and value pair in map
// ForEach executes iteratee funcation for every key and value pair in map.
// Play: https://go.dev/play/p/OaThj6iNVXK
func ForEach[K comparable, V any](m map[K]V, iteratee func(key K, value V)) {
for k, v := range m {
iteratee(k, v)
}
}
// Filter iterates over map, return a new map contains all key and value pairs pass the predicate function
// Filter iterates over map, return a new map contains all key and value pairs pass the predicate function.
// Play: https://go.dev/play/p/fSvF3wxuNG7
func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool) map[K]V {
result := make(map[K]V)
@@ -64,7 +69,8 @@ func Filter[K comparable, V any](m map[K]V, predicate func(key K, value V) bool)
return result
}
// Intersect iterates over maps, return a new map of key and value pairs in all given maps
// Intersect iterates over maps, return a new map of key and value pairs in all given maps.
// Play: https://go.dev/play/p/Zld0oj3sjcC
func Intersect[K comparable, V any](maps ...map[K]V) map[K]V {
if len(maps) == 0 {
return map[K]V{}
@@ -85,7 +91,7 @@ func Intersect[K comparable, V any](maps ...map[K]V) map[K]V {
return m
}
reduceMaps := make([]map[K]V, 2, 2)
reduceMaps := make([]map[K]V, 2)
result = reducer(maps[0], maps[1])
for i := 2; i < len(maps); i++ {
@@ -97,7 +103,8 @@ func Intersect[K comparable, V any](maps ...map[K]V) map[K]V {
return result
}
// Minus creates an map of whose key in mapA but not in mapB
// Minus creates a map of whose key in mapA but not in mapB.
// Play: https://go.dev/play/p/3u5U9K7YZ9m
func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V {
result := make(map[K]V)
@@ -109,7 +116,8 @@ func Minus[K comparable, V any](mapA, mapB map[K]V) map[K]V {
return result
}
// IsDisjoint two map are disjoint if they have no keys in common
// IsDisjoint two map are disjoint if they have no keys in common.
// Play: https://go.dev/play/p/N9qgYg_Ho6f
func IsDisjoint[K comparable, V any](mapA, mapB map[K]V) bool {
for k := range mapA {
if _, ok := mapB[k]; ok {
+181
View File
@@ -0,0 +1,181 @@
package maputil
import (
"fmt"
"sort"
)
func ExampleKeys() {
m := map[int]string{
1: "a",
2: "a",
3: "b",
4: "c",
5: "d",
}
keys := Keys(m)
sort.Ints(keys)
fmt.Println(keys)
// Output:
// [1 2 3 4 5]
}
func ExampleValues() {
m := map[int]string{
1: "a",
2: "a",
3: "b",
4: "c",
5: "d",
}
values := Values(m)
sort.Strings(values)
fmt.Println(values)
// Output:
// [a a b c d]
}
func ExampleMerge() {
m1 := map[int]string{
1: "a",
2: "b",
}
m2 := map[int]string{
1: "c",
3: "d",
}
result := Merge(m1, m2)
fmt.Println(result)
// Output:
// map[1:c 2:b 3:d]
}
func ExampleForEach() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
}
var sum int
ForEach(m, func(_ string, value int) {
sum += value
})
fmt.Println(sum)
// Output:
// 10
}
func ExampleFilter() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
}
isEven := func(_ string, value int) bool {
return value%2 == 0
}
result := Filter(m, isEven)
fmt.Println(result)
// Output:
// map[b:2 d:4]
}
func ExampleIntersect() {
m1 := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
m2 := map[string]int{
"a": 1,
"b": 2,
"c": 6,
"d": 7,
}
m3 := map[string]int{
"a": 1,
"b": 9,
"e": 9,
}
result1 := Intersect(m1)
result2 := Intersect(m1, m2)
result3 := Intersect(m1, m2, m3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// map[a:1 b:2 c:3]
// map[a:1 b:2]
// map[a:1]
}
func ExampleMinus() {
m1 := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
m2 := map[string]int{
"a": 11,
"b": 22,
"d": 33,
}
result := Minus(m1, m2)
fmt.Println(result)
// Output:
// map[c:3]
}
func ExampleIsDisjoint() {
m1 := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
m2 := map[string]int{
"d": 22,
}
m3 := map[string]int{
"a": 22,
}
result1 := IsDisjoint(m1, m2)
result2 := IsDisjoint(m1, m3)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
+29 -17
View File
@@ -10,10 +10,11 @@ import (
"strconv"
"strings"
"github.com/duke-git/lancet/v2/lancetconstraints"
"golang.org/x/exp/constraints"
)
// Exponent calculate x^n
// Exponent calculate x^n.
// Play: https://go.dev/play/p/uF3HGNPk8wr
func Exponent(x, n int64) int64 {
if n == 0 {
return 1
@@ -28,7 +29,8 @@ func Exponent(x, n int64) int64 {
return t * t
}
// Fibonacci calculate fibonacci number before n
// Fibonacci calculate fibonacci number before n.
// Play: https://go.dev/play/p/IscseUNMuUc
func Fibonacci(first, second, n int) int {
if n <= 0 {
return 0
@@ -42,7 +44,8 @@ func Fibonacci(first, second, n int) int {
}
}
// Factorial calculate x!
// Factorial calculate x!.
// Play: https://go.dev/play/p/tt6LdOK67Nx
func Factorial(x uint) uint {
var f uint = 1
for ; x > 1; x-- {
@@ -51,18 +54,20 @@ func Factorial(x uint) uint {
return f
}
// Percent calculate the percentage of val to total
// Percent calculate the percentage of value to total.
// Play: Todo
func Percent(val, total float64, n int) float64 {
if total == 0 {
return float64(0)
}
tmp := val / total * 100
tmp := val / total
result := RoundToFloat(tmp, n)
return result
}
// RoundToString round up to n decimal places
// RoundToString round up to n decimal places.
// Play: https://go.dev/play/p/kZwpBRAcllO
func RoundToString(x float64, n int) string {
tmp := math.Pow(10.0, float64(n))
x *= tmp
@@ -71,7 +76,8 @@ func RoundToString(x float64, n int) string {
return result
}
// RoundToFloat round up to n decimal places
// RoundToFloat round up to n decimal places.
// Play: https://go.dev/play/p/ghyb528JRJL
func RoundToFloat(x float64, n int) float64 {
tmp := math.Pow(10.0, float64(n))
x *= tmp
@@ -79,7 +85,8 @@ func RoundToFloat(x float64, n int) float64 {
return x / tmp
}
// TruncRound round off n decimal places
// TruncRound round off n decimal places.
// Play: https://go.dev/play/p/aumarSHIGzP
func TruncRound(x float64, n int) float64 {
floatStr := fmt.Sprintf("%."+strconv.Itoa(n+1)+"f", x)
temp := strings.Split(floatStr, ".")
@@ -93,8 +100,9 @@ func TruncRound(x float64, n int) float64 {
return result
}
// Max return max value of params
func Max[T lancetconstraints.Number](numbers ...T) T {
// Max return max value of numbers.
// Play: https://go.dev/play/p/cN8DHI0rTkH
func Max[T constraints.Integer | constraints.Float](numbers ...T) T {
max := numbers[0]
for _, v := range numbers {
@@ -106,7 +114,8 @@ func Max[T lancetconstraints.Number](numbers ...T) T {
return max
}
// MaxBy search the maximum value of a slice using the given comparator function.
// MaxBy return the maximum value of a slice using the given comparator function.
// Play: https://go.dev/play/p/pbe2MT-7DV2
func MaxBy[T any](slice []T, comparator func(T, T) bool) T {
var max T
@@ -127,8 +136,9 @@ func MaxBy[T any](slice []T, comparator func(T, T) bool) T {
return max
}
// Min return min value of params
func Min[T lancetconstraints.Number](numbers ...T) T {
// Min return min value of numbers.
// Play: https://go.dev/play/p/21BER_mlGUj
func Min[T constraints.Integer | constraints.Float](numbers ...T) T {
min := numbers[0]
for _, v := range numbers {
@@ -140,7 +150,8 @@ func Min[T lancetconstraints.Number](numbers ...T) T {
return min
}
// MinBy search the minimum value of a slice using the given comparator function.
// MinBy return the minimum value of a slice using the given comparator function.
// Play: https://go.dev/play/p/XuJDKrDdglW
func MinBy[T any](slice []T, comparator func(T, T) bool) T {
var min T
@@ -161,8 +172,9 @@ func MinBy[T any](slice []T, comparator func(T, T) bool) T {
return min
}
// Average return average value of params
func Average[T lancetconstraints.Number](numbers ...T) T {
// Average return average value of numbers.
// Play: https://go.dev/play/p/Vv7LBwER-pz
func Average[T constraints.Integer | constraints.Float](numbers ...T) T {
var sum T
n := T(len(numbers))
+187
View File
@@ -0,0 +1,187 @@
package mathutil
import "fmt"
func ExampleExponent() {
result1 := Exponent(10, 0)
result2 := Exponent(10, 1)
result3 := Exponent(10, 2)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 10
// 100
}
func ExampleFibonacci() {
result1 := Fibonacci(1, 1, 1)
result2 := Fibonacci(1, 1, 2)
result3 := Fibonacci(1, 1, 5)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 1
// 5
}
func ExampleFactorial() {
result1 := Factorial(1)
result2 := Factorial(2)
result3 := Factorial(3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 1
// 2
// 6
}
func ExamplePercent() {
result1 := Percent(1, 2, 2)
result2 := Percent(0.1, 0.3, 2)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 0.5
// 0.33
}
func ExampleRoundToFloat() {
result1 := RoundToFloat(0.124, 2)
result2 := RoundToFloat(0.125, 2)
result3 := RoundToFloat(0.125, 3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.12
// 0.13
// 0.125
}
func ExampleRoundToString() {
result1 := RoundToString(0.124, 2)
result2 := RoundToString(0.125, 2)
result3 := RoundToString(0.125, 3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.12
// 0.13
// 0.125
}
func ExampleTruncRound() {
result1 := TruncRound(0.124, 2)
result2 := TruncRound(0.125, 2)
result3 := TruncRound(0.125, 3)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// 0.12
// 0.12
// 0.125
}
func ExampleAverage() {
result1 := Average(1, 2)
result2 := RoundToFloat(Average(1.2, 1.4), 1)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 1
// 1.3
}
func ExampleMax() {
result1 := Max(1, 2, 3)
result2 := Max(1.2, 1.4, 1.1, 1.4)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 3
// 1.4
}
func ExampleMaxBy() {
result1 := MaxBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
return len(v1) > len(v2)
})
result2 := MaxBy([]string{"abd", "abc", "ab"}, func(v1, v2 string) bool {
return len(v1) > len(v2)
})
result3 := MaxBy([]string{}, func(v1, v2 string) bool {
return len(v1) > len(v2)
})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// abc
// abd
//
}
func ExampleMin() {
result1 := Min(1, 2, 3)
result2 := Min(1.2, 1.4, 1.1, 1.4)
fmt.Println(result1)
fmt.Println(result2)
// Output:
// 1
// 1.1
}
func ExampleMinBy() {
result1 := MinBy([]string{"a", "ab", "abc"}, func(v1, v2 string) bool {
return len(v1) < len(v2)
})
result2 := MinBy([]string{"ab", "ac", "abc"}, func(v1, v2 string) bool {
return len(v1) < len(v2)
})
result3 := MinBy([]string{}, func(v1, v2 string) bool {
return len(v1) < len(v2)
})
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// a
// ab
//
}
+2 -2
View File
@@ -35,8 +35,8 @@ func TestFactorial(t *testing.T) {
func TestPercent(t *testing.T) {
assert := internal.NewAssert(t, "TestPercent")
assert.Equal(float64(50), Percent(1, 2, 2))
assert.Equal(float64(33.33), Percent(0.1, 0.3, 2))
assert.Equal(0.5, Percent(1, 2, 2))
assert.Equal(0.33, Percent(0.1, 0.3, 2))
}
func TestRoundToFloat(t *testing.T) {
+7 -3
View File
@@ -6,7 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"reflect"
@@ -108,7 +108,11 @@ func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, err
client.setTLS(rawUrl)
client.setHeader(req, request.Headers)
client.setQueryParam(req, rawUrl, request.QueryParams)
err = client.setQueryParam(req, rawUrl, request.QueryParams)
if err != nil {
return nil, err
}
if request.FormData != nil {
client.setFormData(req, request.FormData)
@@ -177,7 +181,7 @@ func (client *HttpClient) setQueryParam(req *http.Request, reqUrl string, queryP
func (client *HttpClient) setFormData(req *http.Request, values url.Values) {
formData := []byte(values.Encode())
req.Body = ioutil.NopCloser(bytes.NewReader(formData))
req.Body = io.NopCloser(bytes.NewReader(formData))
req.ContentLength = int64(len(formData))
}
+7 -4
View File
@@ -1,7 +1,7 @@
package netutil
import (
"io/ioutil"
"io"
"log"
"net/http"
"net/url"
@@ -32,7 +32,10 @@ func TestHttpClient_Get(t *testing.T) {
}
var todo Todo
httpClient.DecodeResponse(resp, &todo)
err = httpClient.DecodeResponse(resp, &todo)
if err != nil {
t.Log(err)
}
assert.Equal(1, todo.Id)
}
@@ -58,7 +61,7 @@ func TestHttpClent_Post(t *testing.T) {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
@@ -90,6 +93,6 @@ func TestStructToUrlValues(t *testing.T) {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", string(body))
}
+15 -17
View File
@@ -2,8 +2,9 @@ package netutil
import (
"encoding/json"
"io/ioutil"
"io"
"log"
"net/url"
"testing"
"github.com/duke-git/lancet/v2/internal"
@@ -20,7 +21,7 @@ func TestHttpGet(t *testing.T) {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
@@ -40,7 +41,7 @@ func TestHttpPost(t *testing.T) {
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
@@ -50,23 +51,20 @@ func TestHttpPostFormData(t *testing.T) {
// "Content-Type": "application/x-www-form-urlencoded",
"Content-Type": "multipart/form-data",
}
type Todo struct {
UserId int `json:"userId"`
Title string `json:"title"`
}
// postData := url.Values{}
// postData.Add("userId", "1")
// postData.Add("title", "TestAddToDo")
postData := make(map[string]string)
postData["userId"] = "1"
postData["title"] = "title"
postData := url.Values{}
postData.Add("userId", "1")
postData.Add("title", "TestToDo")
// postData := make(map[string]string)
// postData["userId"] = "1"
// postData["title"] = "title"
resp, err := HttpPost(apiUrl, header, postData, nil)
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
@@ -87,7 +85,7 @@ func TestHttpPut(t *testing.T) {
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
@@ -108,7 +106,7 @@ func TestHttpPatch(t *testing.T) {
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
@@ -118,7 +116,7 @@ func TestHttpDelete(t *testing.T) {
if err != nil {
log.Fatal(err)
}
body, _ := ioutil.ReadAll(resp.Body)
body, _ := io.ReadAll(resp.Body)
t.Log("response: ", resp.StatusCode, string(body))
}
+2 -2
View File
@@ -2,7 +2,7 @@ package netutil
import (
"encoding/json"
"io/ioutil"
"io"
"net"
"net/http"
"net/url"
@@ -55,7 +55,7 @@ func GetPublicIpInfo() (*PublicIpInfo, error) {
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

Some files were not shown because too many files have changed in this diff Show More