github.com/gogf/gf/v2@v2.7.4/container/garray/garray_normal_str.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package garray 8 9 import ( 10 "bytes" 11 "math" 12 "sort" 13 "strings" 14 15 "github.com/gogf/gf/v2/errors/gcode" 16 "github.com/gogf/gf/v2/errors/gerror" 17 "github.com/gogf/gf/v2/internal/json" 18 "github.com/gogf/gf/v2/internal/rwmutex" 19 "github.com/gogf/gf/v2/text/gstr" 20 "github.com/gogf/gf/v2/util/gconv" 21 "github.com/gogf/gf/v2/util/grand" 22 ) 23 24 // StrArray is a golang string array with rich features. 25 // It contains a concurrent-safe/unsafe switch, which should be set 26 // when its initialization and cannot be changed then. 27 type StrArray struct { 28 mu rwmutex.RWMutex 29 array []string 30 } 31 32 // NewStrArray creates and returns an empty array. 33 // The parameter `safe` is used to specify whether using array in concurrent-safety, 34 // which is false in default. 35 func NewStrArray(safe ...bool) *StrArray { 36 return NewStrArraySize(0, 0, safe...) 37 } 38 39 // NewStrArraySize create and returns an array with given size and cap. 40 // The parameter `safe` is used to specify whether using array in concurrent-safety, 41 // which is false in default. 42 func NewStrArraySize(size int, cap int, safe ...bool) *StrArray { 43 return &StrArray{ 44 mu: rwmutex.Create(safe...), 45 array: make([]string, size, cap), 46 } 47 } 48 49 // NewStrArrayFrom creates and returns an array with given slice `array`. 50 // The parameter `safe` is used to specify whether using array in concurrent-safety, 51 // which is false in default. 52 func NewStrArrayFrom(array []string, safe ...bool) *StrArray { 53 return &StrArray{ 54 mu: rwmutex.Create(safe...), 55 array: array, 56 } 57 } 58 59 // NewStrArrayFromCopy creates and returns an array from a copy of given slice `array`. 60 // The parameter `safe` is used to specify whether using array in concurrent-safety, 61 // which is false in default. 62 func NewStrArrayFromCopy(array []string, safe ...bool) *StrArray { 63 newArray := make([]string, len(array)) 64 copy(newArray, array) 65 return &StrArray{ 66 mu: rwmutex.Create(safe...), 67 array: newArray, 68 } 69 } 70 71 // At returns the value by the specified index. 72 // If the given `index` is out of range of the array, it returns an empty string. 73 func (a *StrArray) At(index int) (value string) { 74 value, _ = a.Get(index) 75 return 76 } 77 78 // Get returns the value by the specified index. 79 // If the given `index` is out of range of the array, the `found` is false. 80 func (a *StrArray) Get(index int) (value string, found bool) { 81 a.mu.RLock() 82 defer a.mu.RUnlock() 83 if index < 0 || index >= len(a.array) { 84 return "", false 85 } 86 return a.array[index], true 87 } 88 89 // Set sets value to specified index. 90 func (a *StrArray) Set(index int, value string) error { 91 a.mu.Lock() 92 defer a.mu.Unlock() 93 if index < 0 || index >= len(a.array) { 94 return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array)) 95 } 96 a.array[index] = value 97 return nil 98 } 99 100 // SetArray sets the underlying slice array with the given `array`. 101 func (a *StrArray) SetArray(array []string) *StrArray { 102 a.mu.Lock() 103 defer a.mu.Unlock() 104 a.array = array 105 return a 106 } 107 108 // Replace replaces the array items by given `array` from the beginning of array. 109 func (a *StrArray) Replace(array []string) *StrArray { 110 a.mu.Lock() 111 defer a.mu.Unlock() 112 max := len(array) 113 if max > len(a.array) { 114 max = len(a.array) 115 } 116 for i := 0; i < max; i++ { 117 a.array[i] = array[i] 118 } 119 return a 120 } 121 122 // Sum returns the sum of values in an array. 123 func (a *StrArray) Sum() (sum int) { 124 a.mu.RLock() 125 defer a.mu.RUnlock() 126 for _, v := range a.array { 127 sum += gconv.Int(v) 128 } 129 return 130 } 131 132 // Sort sorts the array in increasing order. 133 // The parameter `reverse` controls whether sort 134 // in increasing order(default) or decreasing order 135 func (a *StrArray) Sort(reverse ...bool) *StrArray { 136 a.mu.Lock() 137 defer a.mu.Unlock() 138 if len(reverse) > 0 && reverse[0] { 139 sort.Slice(a.array, func(i, j int) bool { 140 return strings.Compare(a.array[i], a.array[j]) >= 0 141 }) 142 } else { 143 sort.Strings(a.array) 144 } 145 return a 146 } 147 148 // SortFunc sorts the array by custom function `less`. 149 func (a *StrArray) SortFunc(less func(v1, v2 string) bool) *StrArray { 150 a.mu.Lock() 151 defer a.mu.Unlock() 152 sort.Slice(a.array, func(i, j int) bool { 153 return less(a.array[i], a.array[j]) 154 }) 155 return a 156 } 157 158 // InsertBefore inserts the `values` to the front of `index`. 159 func (a *StrArray) InsertBefore(index int, values ...string) error { 160 a.mu.Lock() 161 defer a.mu.Unlock() 162 if index < 0 || index >= len(a.array) { 163 return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array)) 164 } 165 rear := append([]string{}, a.array[index:]...) 166 a.array = append(a.array[0:index], values...) 167 a.array = append(a.array, rear...) 168 return nil 169 } 170 171 // InsertAfter inserts the `values` to the back of `index`. 172 func (a *StrArray) InsertAfter(index int, values ...string) error { 173 a.mu.Lock() 174 defer a.mu.Unlock() 175 if index < 0 || index >= len(a.array) { 176 return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array)) 177 } 178 rear := append([]string{}, a.array[index+1:]...) 179 a.array = append(a.array[0:index+1], values...) 180 a.array = append(a.array, rear...) 181 return nil 182 } 183 184 // Remove removes an item by index. 185 // If the given `index` is out of range of the array, the `found` is false. 186 func (a *StrArray) Remove(index int) (value string, found bool) { 187 a.mu.Lock() 188 defer a.mu.Unlock() 189 return a.doRemoveWithoutLock(index) 190 } 191 192 // doRemoveWithoutLock removes an item by index without lock. 193 func (a *StrArray) doRemoveWithoutLock(index int) (value string, found bool) { 194 if index < 0 || index >= len(a.array) { 195 return "", false 196 } 197 // Determine array boundaries when deleting to improve deletion efficiency. 198 if index == 0 { 199 value := a.array[0] 200 a.array = a.array[1:] 201 return value, true 202 } else if index == len(a.array)-1 { 203 value := a.array[index] 204 a.array = a.array[:index] 205 return value, true 206 } 207 // If it is a non-boundary delete, 208 // it will involve the creation of an array, 209 // then the deletion is less efficient. 210 value = a.array[index] 211 a.array = append(a.array[:index], a.array[index+1:]...) 212 return value, true 213 } 214 215 // RemoveValue removes an item by value. 216 // It returns true if value is found in the array, or else false if not found. 217 func (a *StrArray) RemoveValue(value string) bool { 218 if i := a.Search(value); i != -1 { 219 _, found := a.Remove(i) 220 return found 221 } 222 return false 223 } 224 225 // RemoveValues removes multiple items by `values`. 226 func (a *StrArray) RemoveValues(values ...string) { 227 a.mu.Lock() 228 defer a.mu.Unlock() 229 for _, value := range values { 230 if i := a.doSearchWithoutLock(value); i != -1 { 231 a.doRemoveWithoutLock(i) 232 } 233 } 234 } 235 236 // PushLeft pushes one or multiple items to the beginning of array. 237 func (a *StrArray) PushLeft(value ...string) *StrArray { 238 a.mu.Lock() 239 a.array = append(value, a.array...) 240 a.mu.Unlock() 241 return a 242 } 243 244 // PushRight pushes one or multiple items to the end of array. 245 // It equals to Append. 246 func (a *StrArray) PushRight(value ...string) *StrArray { 247 a.mu.Lock() 248 a.array = append(a.array, value...) 249 a.mu.Unlock() 250 return a 251 } 252 253 // PopLeft pops and returns an item from the beginning of array. 254 // Note that if the array is empty, the `found` is false. 255 func (a *StrArray) PopLeft() (value string, found bool) { 256 a.mu.Lock() 257 defer a.mu.Unlock() 258 if len(a.array) == 0 { 259 return "", false 260 } 261 value = a.array[0] 262 a.array = a.array[1:] 263 return value, true 264 } 265 266 // PopRight pops and returns an item from the end of array. 267 // Note that if the array is empty, the `found` is false. 268 func (a *StrArray) PopRight() (value string, found bool) { 269 a.mu.Lock() 270 defer a.mu.Unlock() 271 index := len(a.array) - 1 272 if index < 0 { 273 return "", false 274 } 275 value = a.array[index] 276 a.array = a.array[:index] 277 return value, true 278 } 279 280 // PopRand randomly pops and return an item out of array. 281 // Note that if the array is empty, the `found` is false. 282 func (a *StrArray) PopRand() (value string, found bool) { 283 a.mu.Lock() 284 defer a.mu.Unlock() 285 return a.doRemoveWithoutLock(grand.Intn(len(a.array))) 286 } 287 288 // PopRands randomly pops and returns `size` items out of array. 289 // If the given `size` is greater than size of the array, it returns all elements of the array. 290 // Note that if given `size` <= 0 or the array is empty, it returns nil. 291 func (a *StrArray) PopRands(size int) []string { 292 a.mu.Lock() 293 defer a.mu.Unlock() 294 if size <= 0 || len(a.array) == 0 { 295 return nil 296 } 297 if size >= len(a.array) { 298 size = len(a.array) 299 } 300 array := make([]string, size) 301 for i := 0; i < size; i++ { 302 array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array))) 303 } 304 return array 305 } 306 307 // PopLefts pops and returns `size` items from the beginning of array. 308 // If the given `size` is greater than size of the array, it returns all elements of the array. 309 // Note that if given `size` <= 0 or the array is empty, it returns nil. 310 func (a *StrArray) PopLefts(size int) []string { 311 a.mu.Lock() 312 defer a.mu.Unlock() 313 if size <= 0 || len(a.array) == 0 { 314 return nil 315 } 316 if size >= len(a.array) { 317 array := a.array 318 a.array = a.array[:0] 319 return array 320 } 321 value := a.array[0:size] 322 a.array = a.array[size:] 323 return value 324 } 325 326 // PopRights pops and returns `size` items from the end of array. 327 // If the given `size` is greater than size of the array, it returns all elements of the array. 328 // Note that if given `size` <= 0 or the array is empty, it returns nil. 329 func (a *StrArray) PopRights(size int) []string { 330 a.mu.Lock() 331 defer a.mu.Unlock() 332 if size <= 0 || len(a.array) == 0 { 333 return nil 334 } 335 index := len(a.array) - size 336 if index <= 0 { 337 array := a.array 338 a.array = a.array[:0] 339 return array 340 } 341 value := a.array[index:] 342 a.array = a.array[:index] 343 return value 344 } 345 346 // Range picks and returns items by range, like array[start:end]. 347 // Notice, if in concurrent-safe usage, it returns a copy of slice; 348 // else a pointer to the underlying data. 349 // 350 // If `end` is negative, then the offset will start from the end of array. 351 // If `end` is omitted, then the sequence will have everything from start up 352 // until the end of the array. 353 func (a *StrArray) Range(start int, end ...int) []string { 354 a.mu.RLock() 355 defer a.mu.RUnlock() 356 offsetEnd := len(a.array) 357 if len(end) > 0 && end[0] < offsetEnd { 358 offsetEnd = end[0] 359 } 360 if start > offsetEnd { 361 return nil 362 } 363 if start < 0 { 364 start = 0 365 } 366 array := ([]string)(nil) 367 if a.mu.IsSafe() { 368 array = make([]string, offsetEnd-start) 369 copy(array, a.array[start:offsetEnd]) 370 } else { 371 array = a.array[start:offsetEnd] 372 } 373 return array 374 } 375 376 // SubSlice returns a slice of elements from the array as specified 377 // by the `offset` and `size` parameters. 378 // If in concurrent safe usage, it returns a copy of the slice; else a pointer. 379 // 380 // If offset is non-negative, the sequence will start at that offset in the array. 381 // If offset is negative, the sequence will start that far from the end of the array. 382 // 383 // If length is given and is positive, then the sequence will have up to that many elements in it. 384 // If the array is shorter than the length, then only the available array elements will be present. 385 // If length is given and is negative then the sequence will stop that many elements from the end of the array. 386 // If it is omitted, then the sequence will have everything from offset up until the end of the array. 387 // 388 // Any possibility crossing the left border of array, it will fail. 389 func (a *StrArray) SubSlice(offset int, length ...int) []string { 390 a.mu.RLock() 391 defer a.mu.RUnlock() 392 size := len(a.array) 393 if len(length) > 0 { 394 size = length[0] 395 } 396 if offset > len(a.array) { 397 return nil 398 } 399 if offset < 0 { 400 offset = len(a.array) + offset 401 if offset < 0 { 402 return nil 403 } 404 } 405 if size < 0 { 406 offset += size 407 size = -size 408 if offset < 0 { 409 return nil 410 } 411 } 412 end := offset + size 413 if end > len(a.array) { 414 end = len(a.array) 415 size = len(a.array) - offset 416 } 417 if a.mu.IsSafe() { 418 s := make([]string, size) 419 copy(s, a.array[offset:]) 420 return s 421 } 422 return a.array[offset:end] 423 } 424 425 // Append is alias of PushRight,please See PushRight. 426 func (a *StrArray) Append(value ...string) *StrArray { 427 a.mu.Lock() 428 a.array = append(a.array, value...) 429 a.mu.Unlock() 430 return a 431 } 432 433 // Len returns the length of array. 434 func (a *StrArray) Len() int { 435 a.mu.RLock() 436 length := len(a.array) 437 a.mu.RUnlock() 438 return length 439 } 440 441 // Slice returns the underlying data of array. 442 // Note that, if it's in concurrent-safe usage, it returns a copy of underlying data, 443 // or else a pointer to the underlying data. 444 func (a *StrArray) Slice() []string { 445 array := ([]string)(nil) 446 if a.mu.IsSafe() { 447 a.mu.RLock() 448 defer a.mu.RUnlock() 449 array = make([]string, len(a.array)) 450 copy(array, a.array) 451 } else { 452 array = a.array 453 } 454 return array 455 } 456 457 // Interfaces returns current array as []interface{}. 458 func (a *StrArray) Interfaces() []interface{} { 459 a.mu.RLock() 460 defer a.mu.RUnlock() 461 array := make([]interface{}, len(a.array)) 462 for k, v := range a.array { 463 array[k] = v 464 } 465 return array 466 } 467 468 // Clone returns a new array, which is a copy of current array. 469 func (a *StrArray) Clone() (newArray *StrArray) { 470 a.mu.RLock() 471 array := make([]string, len(a.array)) 472 copy(array, a.array) 473 a.mu.RUnlock() 474 return NewStrArrayFrom(array, a.mu.IsSafe()) 475 } 476 477 // Clear deletes all items of current array. 478 func (a *StrArray) Clear() *StrArray { 479 a.mu.Lock() 480 if len(a.array) > 0 { 481 a.array = make([]string, 0) 482 } 483 a.mu.Unlock() 484 return a 485 } 486 487 // Contains checks whether a value exists in the array. 488 func (a *StrArray) Contains(value string) bool { 489 return a.Search(value) != -1 490 } 491 492 // ContainsI checks whether a value exists in the array with case-insensitively. 493 // Note that it internally iterates the whole array to do the comparison with case-insensitively. 494 func (a *StrArray) ContainsI(value string) bool { 495 a.mu.RLock() 496 defer a.mu.RUnlock() 497 if len(a.array) == 0 { 498 return false 499 } 500 for _, v := range a.array { 501 if strings.EqualFold(v, value) { 502 return true 503 } 504 } 505 return false 506 } 507 508 // Search searches array by `value`, returns the index of `value`, 509 // or returns -1 if not exists. 510 func (a *StrArray) Search(value string) int { 511 a.mu.RLock() 512 defer a.mu.RUnlock() 513 return a.doSearchWithoutLock(value) 514 } 515 516 func (a *StrArray) doSearchWithoutLock(value string) int { 517 if len(a.array) == 0 { 518 return -1 519 } 520 result := -1 521 for index, v := range a.array { 522 if strings.Compare(v, value) == 0 { 523 result = index 524 break 525 } 526 } 527 return result 528 } 529 530 // Unique uniques the array, clear repeated items. 531 // Example: [1,1,2,3,2] -> [1,2,3] 532 func (a *StrArray) Unique() *StrArray { 533 a.mu.Lock() 534 defer a.mu.Unlock() 535 if len(a.array) == 0 { 536 return a 537 } 538 var ( 539 ok bool 540 temp string 541 uniqueSet = make(map[string]struct{}) 542 uniqueArray = make([]string, 0, len(a.array)) 543 ) 544 for i := 0; i < len(a.array); i++ { 545 temp = a.array[i] 546 if _, ok = uniqueSet[temp]; ok { 547 continue 548 } 549 uniqueSet[temp] = struct{}{} 550 uniqueArray = append(uniqueArray, temp) 551 } 552 a.array = uniqueArray 553 return a 554 } 555 556 // LockFunc locks writing by callback function `f`. 557 func (a *StrArray) LockFunc(f func(array []string)) *StrArray { 558 a.mu.Lock() 559 defer a.mu.Unlock() 560 f(a.array) 561 return a 562 } 563 564 // RLockFunc locks reading by callback function `f`. 565 func (a *StrArray) RLockFunc(f func(array []string)) *StrArray { 566 a.mu.RLock() 567 defer a.mu.RUnlock() 568 f(a.array) 569 return a 570 } 571 572 // Merge merges `array` into current array. 573 // The parameter `array` can be any garray or slice type. 574 // The difference between Merge and Append is Append supports only specified slice type, 575 // but Merge supports more parameter types. 576 func (a *StrArray) Merge(array interface{}) *StrArray { 577 return a.Append(gconv.Strings(array)...) 578 } 579 580 // Fill fills an array with num entries of the value `value`, 581 // keys starting at the `startIndex` parameter. 582 func (a *StrArray) Fill(startIndex int, num int, value string) error { 583 a.mu.Lock() 584 defer a.mu.Unlock() 585 if startIndex < 0 || startIndex > len(a.array) { 586 return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", startIndex, len(a.array)) 587 } 588 for i := startIndex; i < startIndex+num; i++ { 589 if i > len(a.array)-1 { 590 a.array = append(a.array, value) 591 } else { 592 a.array[i] = value 593 } 594 } 595 return nil 596 } 597 598 // Chunk splits an array into multiple arrays, 599 // the size of each array is determined by `size`. 600 // The last chunk may contain less than size elements. 601 func (a *StrArray) Chunk(size int) [][]string { 602 if size < 1 { 603 return nil 604 } 605 a.mu.RLock() 606 defer a.mu.RUnlock() 607 length := len(a.array) 608 chunks := int(math.Ceil(float64(length) / float64(size))) 609 var n [][]string 610 for i, end := 0, 0; chunks > 0; chunks-- { 611 end = (i + 1) * size 612 if end > length { 613 end = length 614 } 615 n = append(n, a.array[i*size:end]) 616 i++ 617 } 618 return n 619 } 620 621 // Pad pads array to the specified length with `value`. 622 // If size is positive then the array is padded on the right, or negative on the left. 623 // If the absolute value of `size` is less than or equal to the length of the array 624 // then no padding takes place. 625 func (a *StrArray) Pad(size int, value string) *StrArray { 626 a.mu.Lock() 627 defer a.mu.Unlock() 628 if size == 0 || (size > 0 && size < len(a.array)) || (size < 0 && size > -len(a.array)) { 629 return a 630 } 631 n := size 632 if size < 0 { 633 n = -size 634 } 635 n -= len(a.array) 636 tmp := make([]string, n) 637 for i := 0; i < n; i++ { 638 tmp[i] = value 639 } 640 if size > 0 { 641 a.array = append(a.array, tmp...) 642 } else { 643 a.array = append(tmp, a.array...) 644 } 645 return a 646 } 647 648 // Rand randomly returns one item from array(no deleting). 649 func (a *StrArray) Rand() (value string, found bool) { 650 a.mu.RLock() 651 defer a.mu.RUnlock() 652 if len(a.array) == 0 { 653 return "", false 654 } 655 return a.array[grand.Intn(len(a.array))], true 656 } 657 658 // Rands randomly returns `size` items from array(no deleting). 659 func (a *StrArray) Rands(size int) []string { 660 a.mu.RLock() 661 defer a.mu.RUnlock() 662 if size <= 0 || len(a.array) == 0 { 663 return nil 664 } 665 array := make([]string, size) 666 for i := 0; i < size; i++ { 667 array[i] = a.array[grand.Intn(len(a.array))] 668 } 669 return array 670 } 671 672 // Shuffle randomly shuffles the array. 673 func (a *StrArray) Shuffle() *StrArray { 674 a.mu.Lock() 675 defer a.mu.Unlock() 676 for i, v := range grand.Perm(len(a.array)) { 677 a.array[i], a.array[v] = a.array[v], a.array[i] 678 } 679 return a 680 } 681 682 // Reverse makes array with elements in reverse order. 683 func (a *StrArray) Reverse() *StrArray { 684 a.mu.Lock() 685 defer a.mu.Unlock() 686 for i, j := 0, len(a.array)-1; i < j; i, j = i+1, j-1 { 687 a.array[i], a.array[j] = a.array[j], a.array[i] 688 } 689 return a 690 } 691 692 // Join joins array elements with a string `glue`. 693 func (a *StrArray) Join(glue string) string { 694 a.mu.RLock() 695 defer a.mu.RUnlock() 696 if len(a.array) == 0 { 697 return "" 698 } 699 buffer := bytes.NewBuffer(nil) 700 for k, v := range a.array { 701 buffer.WriteString(v) 702 if k != len(a.array)-1 { 703 buffer.WriteString(glue) 704 } 705 } 706 return buffer.String() 707 } 708 709 // CountValues counts the number of occurrences of all values in the array. 710 func (a *StrArray) CountValues() map[string]int { 711 m := make(map[string]int) 712 a.mu.RLock() 713 defer a.mu.RUnlock() 714 for _, v := range a.array { 715 m[v]++ 716 } 717 return m 718 } 719 720 // Iterator is alias of IteratorAsc. 721 func (a *StrArray) Iterator(f func(k int, v string) bool) { 722 a.IteratorAsc(f) 723 } 724 725 // IteratorAsc iterates the array readonly in ascending order with given callback function `f`. 726 // If `f` returns true, then it continues iterating; or false to stop. 727 func (a *StrArray) IteratorAsc(f func(k int, v string) bool) { 728 a.mu.RLock() 729 defer a.mu.RUnlock() 730 for k, v := range a.array { 731 if !f(k, v) { 732 break 733 } 734 } 735 } 736 737 // IteratorDesc iterates the array readonly in descending order with given callback function `f`. 738 // If `f` returns true, then it continues iterating; or false to stop. 739 func (a *StrArray) IteratorDesc(f func(k int, v string) bool) { 740 a.mu.RLock() 741 defer a.mu.RUnlock() 742 for i := len(a.array) - 1; i >= 0; i-- { 743 if !f(i, a.array[i]) { 744 break 745 } 746 } 747 } 748 749 // String returns current array as a string, which implements like json.Marshal does. 750 func (a *StrArray) String() string { 751 if a == nil { 752 return "" 753 } 754 a.mu.RLock() 755 defer a.mu.RUnlock() 756 buffer := bytes.NewBuffer(nil) 757 buffer.WriteByte('[') 758 for k, v := range a.array { 759 buffer.WriteString(`"` + gstr.QuoteMeta(v, `"\`) + `"`) 760 if k != len(a.array)-1 { 761 buffer.WriteByte(',') 762 } 763 } 764 buffer.WriteByte(']') 765 return buffer.String() 766 } 767 768 // MarshalJSON implements the interface MarshalJSON for json.Marshal. 769 // Note that do not use pointer as its receiver here. 770 func (a StrArray) MarshalJSON() ([]byte, error) { 771 a.mu.RLock() 772 defer a.mu.RUnlock() 773 return json.Marshal(a.array) 774 } 775 776 // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal. 777 func (a *StrArray) UnmarshalJSON(b []byte) error { 778 if a.array == nil { 779 a.array = make([]string, 0) 780 } 781 a.mu.Lock() 782 defer a.mu.Unlock() 783 if err := json.UnmarshalUseNumber(b, &a.array); err != nil { 784 return err 785 } 786 return nil 787 } 788 789 // UnmarshalValue is an interface implement which sets any type of value for array. 790 func (a *StrArray) UnmarshalValue(value interface{}) error { 791 a.mu.Lock() 792 defer a.mu.Unlock() 793 switch value.(type) { 794 case string, []byte: 795 return json.UnmarshalUseNumber(gconv.Bytes(value), &a.array) 796 default: 797 a.array = gconv.SliceStr(value) 798 } 799 return nil 800 } 801 802 // Filter iterates array and filters elements using custom callback function. 803 // It removes the element from array if callback function `filter` returns true, 804 // it or else does nothing and continues iterating. 805 func (a *StrArray) Filter(filter func(index int, value string) bool) *StrArray { 806 a.mu.Lock() 807 defer a.mu.Unlock() 808 for i := 0; i < len(a.array); { 809 if filter(i, a.array[i]) { 810 a.array = append(a.array[:i], a.array[i+1:]...) 811 } else { 812 i++ 813 } 814 } 815 return a 816 } 817 818 // FilterEmpty removes all empty string value of the array. 819 func (a *StrArray) FilterEmpty() *StrArray { 820 a.mu.Lock() 821 defer a.mu.Unlock() 822 for i := 0; i < len(a.array); { 823 if a.array[i] == "" { 824 a.array = append(a.array[:i], a.array[i+1:]...) 825 } else { 826 i++ 827 } 828 } 829 return a 830 } 831 832 // Walk applies a user supplied function `f` to every item of array. 833 func (a *StrArray) Walk(f func(value string) string) *StrArray { 834 a.mu.Lock() 835 defer a.mu.Unlock() 836 for i, v := range a.array { 837 a.array[i] = f(v) 838 } 839 return a 840 } 841 842 // IsEmpty checks whether the array is empty. 843 func (a *StrArray) IsEmpty() bool { 844 return a.Len() == 0 845 } 846 847 // DeepCopy implements interface for deep copy of current type. 848 func (a *StrArray) DeepCopy() interface{} { 849 if a == nil { 850 return nil 851 } 852 a.mu.RLock() 853 defer a.mu.RUnlock() 854 newSlice := make([]string, len(a.array)) 855 copy(newSlice, a.array) 856 return NewStrArrayFrom(newSlice, a.mu.IsSafe()) 857 }