Repository: gookit/goutil

Issue:
Dump: Can dump provide a parameter to control length not to print?
current

```
DnsHostnameStatus: "DISABLED", #len=8
```

want
```
DnsHostnameStatus: "DISABLED",
```

Discussion:

Solution patch:
diff --git a/dump/dumper.go b/dump/dumper.go
index 30030e5..743de99 100644
--- a/dump/dumper.go
+++ b/dump/dumper.go
@@ -186,8 +186,12 @@ func (d *Dumper) printOne(v any) {
 
 	if bts, ok := v.([]byte); ok && d.BytesAsString {
 		strVal := d.ColorTheme.string(string(bts))
-		lenTip := d.ColorTheme.valTip("#len=" + strconv.Itoa(len(bts)) + ",cap=" + strconv.Itoa(cap(bts)))
-		d.printf("[]byte(\"%s\"), %s\n", strVal, lenTip)
+		if d.ShowLen {
+			lenTip := d.ColorTheme.valTip("#len=" + strconv.Itoa(len(bts)) + ",cap=" + strconv.Itoa(cap(bts)))
+			d.printf("[]byte(\"%s\"), %s\n", strVal, lenTip)
+		} else {
+			d.printf("[]byte(\"%s\"),\n", strVal)
+		}
 		return
 	}
 
@@ -244,8 +248,12 @@ func (d *Dumper) printRValue(t reflect.Type, v reflect.Value) {
 		d.printf("%s(%s),%s\n", t.String(), intStr, d.rvStringer(t, v))
 	case reflect.String:
 		strVal := d.ColorTheme.string(v.String())
-		lenTip := d.ColorTheme.valTip("#len=" + strconv.Itoa(v.Len()))
-		d.printf("%s(\"%s\"), %s\n", t.String(), strVal, lenTip)
+		if d.ShowLen {
+			lenTip := d.ColorTheme.valTip("#len=" + strconv.Itoa(v.Len()))
+			d.printf("%s(\"%s\"), %s\n", t.String(), strVal, lenTip)
+		} else {
+			d.printf("%s(\"%s\"),\n", t.String(), strVal)
+		}
 	case reflect.Complex64, reflect.Complex128:
 		d.printf("%#v\n", v.Complex())
 	case reflect.Slice, reflect.Array:
@@ -254,9 +262,12 @@ func (d *Dumper) printRValue(t reflect.Type, v reflect.Value) {
 		}
 
 		eleNum := v.Len()
-		lenTip := d.ColorTheme.valTip("#len=" + strconv.Itoa(eleNum) + ",cap=" + strconv.Itoa(v.Cap()))
-
-		d.write(!isPtr, t.String(), " [ ", lenTip, "\n")
+		if d.ShowLen {
+			lenTip := d.ColorTheme.valTip("#len=" + strconv.Itoa(eleNum) + ",cap=" + strconv.Itoa(v.Cap()))
+			d.write(!isPtr, t.String(), " [ ", lenTip, "\n")
+		} else {
+			d.write(!isPtr, t.String(), " [\n")
+		}
 		d.msValue = false
 
 		for i := 0; i < eleNum; i++ {
@@ -323,9 +334,12 @@ func (d *Dumper) printRValue(t reflect.Type, v reflect.Value) {
 
 		d.indentPrint("},\n")
 	case reflect.Map:
-		lenTip := d.ColorTheme.valTip("#len=" + strconv.Itoa(v.Len()))
-
-		d.write(!isPtr, d.ColorTheme.msType(t.String()), " { ", lenTip, "\n")
+		if d.ShowLen {
+			lenTip := d.ColorTheme.valTip("#len=" + strconv.Itoa(v.Len()))
+			d.write(!isPtr, d.ColorTheme.msType(t.String()), " { ", lenTip, "\n")
+		} else {
+			d.write(!isPtr, d.ColorTheme.msType(t.String()), " {\n")
+		}
 		d.msValue = false
 
 		for _, key := range v.MapKeys() {
diff --git a/dump/options.go b/dump/options.go
index 3deb50c..f23ee69 100644
--- a/dump/options.go
+++ b/dump/options.go
@@ -31,6 +31,8 @@ type Options struct {
 	SkipPrivate bool
 	// BytesAsString dump handle.
 	BytesAsString bool
+	// ShowLen display length information for string, slice, array, map
+	ShowLen bool
 	// MoreLenNL array/slice elements length > MoreLenNL, will wrap new line
 	// MoreLenNL int
 	// MaxElementsNum for a long-long slice or array. The excess will be displayed `...`
@@ -58,6 +60,7 @@ func NewDefaultOptions(out io.Writer, skip int) *Options {
 		CallerSkip: skip,
 		ColorTheme: defaultTheme,
 		// ---
+		ShowLen:        true, // show length by default for backward compatibility
 		MaxElementsNum: 99,
 	}
 }
@@ -117,3 +120,10 @@ func WithoutType() OptionFunc {
 		opt.NoType = true
 	}
 }
+
+// WithoutLen setting. hide length information for string, slice, array, map.
+func WithoutLen() OptionFunc {
+	return func(opt *Options) {
+		opt.ShowLen = false
+	}
+}



Test patch:
diff --git a/dump/dump_test.go b/dump/dump_test.go
index d9940ef..2c3a247 100644
--- a/dump/dump_test.go
+++ b/dump/dump_test.go
@@ -400,3 +400,89 @@ func newBuffer() *bytes.Buffer {
 
 	return buf
 }
+
+func TestWithoutLen(t *testing.T) {
+	is := assert.New(t)
+	buf := new(bytes.Buffer)
+
+	// Test with ShowLen disabled
+	Config(func(d *Options) {
+		d.NoColor = true
+		d.ShowFlag = Fnopos
+	})
+	defer Reset()
+
+	// Test string without length
+	Std().WithOptions(WithoutLen())
+	buf.Reset()
+	Fprint(buf, "DISABLED")
+	is.Eq("string(\"DISABLED\"),\n", buf.String())
+	is.NotContains(buf.String(), "#len")
+
+	// Test slice without length
+	buf.Reset()
+	Fprint(buf, []string{"ab", "cd"})
+	is.NotContains(buf.String(), "#len")
+	is.Contains(buf.String(), "[]string [")
+
+	// Test array without length
+	buf.Reset()
+	arr := [3]int{1, 2, 3}
+	Fprint(buf, arr)
+	is.NotContains(buf.String(), "#len")
+	is.Contains(buf.String(), "[3]int [")
+
+	// Test map without length
+	buf.Reset()
+	Fprint(buf, map[string]string{"key": "val"})
+	is.NotContains(buf.String(), "#len")
+	is.Contains(buf.String(), "map[string]string {")
+
+	// Test struct field with string without length
+	buf.Reset()
+	Fprint(buf, struct {
+		Name string
+	}{
+		"test",
+	})
+	is.NotContains(buf.String(), "#len")
+	is.Contains(buf.String(), "Name: string(\"test\"),")
+
+	// Test BytesAsString without length
+	Std().WithOptions(BytesAsString(), WithoutLen())
+	buf.Reset()
+	Fprint(buf, []byte("hello"))
+	is.NotContains(buf.String(), "#len")
+	is.Contains(buf.String(), "[]byte(\"hello\"),")
+}
+
+func TestShowLen_Default(t *testing.T) {
+	is := assert.New(t)
+	buf := new(bytes.Buffer)
+
+	// Test with ShowLen enabled (default behavior)
+	Config(func(d *Options) {
+		d.NoColor = true
+		d.ShowFlag = Fnopos
+	})
+	defer Reset()
+
+	// Verify ShowLen is true by default
+	is.True(Std().ShowLen)
+
+	// Test string with length (default)
+	buf.Reset()
+	Fprint(buf, "DISABLED")
+	is.Contains(buf.String(), "#len=8")
+	is.Eq("string(\"DISABLED\"), #len=8\n", buf.String())
+
+	// Test slice with length (default)
+	buf.Reset()
+	Fprint(buf, []string{"ab", "cd"})
+	is.Contains(buf.String(), "#len=2")
+
+	// Test map with length (default)
+	buf.Reset()
+	Fprint(buf, map[string]int{"key": 123})
+	is.Contains(buf.String(), "#len=1")
+}