improve sliceValidateError.Error performance using switch and strings.Builder (#2765)
fix missing nil pointer check use simpler switch case add missing tests use for-loop instead of range add benchmark test codes
This commit is contained in:
		| @ -20,15 +20,27 @@ type defaultValidator struct { | |||||||
|  |  | ||||||
| type sliceValidateError []error | type sliceValidateError []error | ||||||
|  |  | ||||||
|  | // Error concatenates all error elements in sliceValidateError into a single string separated by \n. | ||||||
| func (err sliceValidateError) Error() string { | func (err sliceValidateError) Error() string { | ||||||
| 	var errMsgs []string | 	n := len(err) | ||||||
| 	for i, e := range err { | 	switch n { | ||||||
| 		if e == nil { | 	case 0: | ||||||
| 			continue | 		return "" | ||||||
|  | 	default: | ||||||
|  | 		var b strings.Builder | ||||||
|  | 		if err[0] != nil { | ||||||
|  | 			fmt.Fprintf(&b, "[%d]: %s", 0, err[0].Error()) | ||||||
| 		} | 		} | ||||||
| 		errMsgs = append(errMsgs, fmt.Sprintf("[%d]: %s", i, e.Error())) | 		if n > 1 { | ||||||
|  | 			for i := 1; i < n; i++ { | ||||||
|  | 				if err[i] != nil { | ||||||
|  | 					b.WriteString("\n") | ||||||
|  | 					fmt.Fprintf(&b, "[%d]: %s", i, err[i].Error()) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return b.String() | ||||||
| 	} | 	} | ||||||
| 	return strings.Join(errMsgs, "\n") |  | ||||||
| } | } | ||||||
|  |  | ||||||
| var _ StructValidator = &defaultValidator{} | var _ StructValidator = &defaultValidator{} | ||||||
|  | |||||||
							
								
								
									
										20
									
								
								binding/default_validator_benchmark_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								binding/default_validator_benchmark_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | package binding | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"strconv" | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func BenchmarkSliceValidateError(b *testing.B) { | ||||||
|  | 	const size int = 100 | ||||||
|  | 	for i := 0; i < b.N; i++ { | ||||||
|  | 		e := make(sliceValidateError, size) | ||||||
|  | 		for j := 0; j < size; j++ { | ||||||
|  | 			e[j] = errors.New(strconv.Itoa(j)) | ||||||
|  | 		} | ||||||
|  | 		if len(e.Error()) == 0 { | ||||||
|  | 			b.Errorf("error") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -16,6 +16,26 @@ func TestSliceValidateError(t *testing.T) { | |||||||
| 		want string | 		want string | ||||||
| 	}{ | 	}{ | ||||||
| 		{"has nil elements", sliceValidateError{errors.New("test error"), nil}, "[0]: test error"}, | 		{"has nil elements", sliceValidateError{errors.New("test error"), nil}, "[0]: test error"}, | ||||||
|  | 		{"has zero elements", sliceValidateError{}, ""}, | ||||||
|  | 		{"has one element", sliceValidateError{errors.New("test one error")}, "[0]: test one error"}, | ||||||
|  | 		{"has two elements", | ||||||
|  | 			sliceValidateError{ | ||||||
|  | 				errors.New("first error"), | ||||||
|  | 				errors.New("second error"), | ||||||
|  | 			}, | ||||||
|  | 			"[0]: first error\n[1]: second error", | ||||||
|  | 		}, | ||||||
|  | 		{"has many elements", | ||||||
|  | 			sliceValidateError{ | ||||||
|  | 				errors.New("first error"), | ||||||
|  | 				errors.New("second error"), | ||||||
|  | 				nil, | ||||||
|  | 				nil, | ||||||
|  | 				nil, | ||||||
|  | 				errors.New("last error"), | ||||||
|  | 			}, | ||||||
|  | 			"[0]: first error\n[1]: second error\n[5]: last error", | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
| 	for _, tt := range tests { | 	for _, tt := range tests { | ||||||
| 		t.Run(tt.name, func(t *testing.T) { | 		t.Run(tt.name, func(t *testing.T) { | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user