{"id":393218,"date":"2024-06-29T10:52:53","date_gmt":"2024-06-29T10:52:53","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=393218"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=393218","title":{"rendered":"<span>gookit\/goutil\u200a\u2014\u200areleased v0.6.10, an extension library of common Go\u00a0features<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><code>gookit\/goutil<\/code> An extended library of Go&#8217;s common functionality. Contains: number, string, slice\/array, Map, struct, reflection, text, file, error, time and date, test, CLI, command run, system information, formatting, common information acquisition, etc.<\/p>\n<blockquote>\n<p><strong>Github<\/strong>: <a href=\"https:\/\/github.com\/gookit\/goutil\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gookit\/goutil<\/a><\/p>\n<\/blockquote>\n<h3>v0.6.10 change log<\/h3>\n<blockquote>\n<p>Full changelog <a href=\"https:\/\/github.com\/gookit\/goutil\/compare\/v0.6.9...v0.6.10\" rel=\"noopener noreferrer nofollow\">v0.6.9&#8230;v0.6.10<\/a><\/p>\n<\/blockquote>\n<h4>\u2728 New features<\/h4>\n<ul>\n<li>\n<p>\u2728 feat: testutil &#8212; adds a new child package <code>fakeobj<\/code> to create fake objects for testing<\/p>\n<\/li>\n<li>\n<p>\u2728 feat: testutil &#8212; adds a new function NewEchoServer() to start the echo server<\/p>\n<\/li>\n<li>\n<p>\u2728 feat: byteutil &#8212; Buffer adds more useful methods for ease of use<\/p>\n<\/li>\n<li>\n<p>\u2728 feat: dump &#8212; Special handling of custom int, uint type values, will print instructions in String format<\/p>\n<\/li>\n<li>\n<p>\u2728 feat: fsutil &#8212; adds a new function to Glob() quickly list matching files<\/p>\n<\/li>\n<li>\n<p>\u267b\ufe0f feat: httpreq &#8212; Refactoring the built-in HTTP client httpreq logic<\/p>\n<\/li>\n<\/ul>\n<h4>? Update Adjustments<\/h4>\n<ul>\n<li>\n<p>? up: structs &#8212; Update and support InitDefaults() for struct slice fields that are not null<\/p>\n<\/li>\n<li>\n<p>? up: maputil &#8212; <code>SimpleMerge()<\/code> Supports deep merging of map[string]any data<\/p>\n<\/li>\n<\/ul>\n<h4>Other adjustments<\/h4>\n<ul>\n<li>\n<p>\u2705 test: Update some documentation and fix some unit tests<\/p>\n<\/li>\n<li>\n<p>\u2b06\ufe0f dep: Update <a href=\"http:\/\/golang.org\/x\" rel=\"noopener noreferrer nofollow\">golang.org\/x<\/a> depends on the latest version<\/p>\n<\/li>\n<\/ul>\n<h4>Some feature usage examples<\/h4>\n<h3>dump &#8212; prints custom types<\/h3>\n<p>dump &#8212; special handles custom int, uint type values, and will print instructions in String format<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f6c\/716\/02d\/f6c71602d6341cd075b912ad7034161a.png\" alt=\"dump custom_type.png\" width=\"875\" height=\"324\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f6c\/716\/02d\/f6c71602d6341cd075b912ad7034161a.png\"\/><\/p>\n<div><figcaption>dump custom_type.png<\/figcaption><\/div>\n<\/figure>\n<h3>Initialize the struct<\/h3>\n<ul>\n<li>\n<p>Support for initializing the use of environment variables<\/p>\n<\/li>\n<li>\n<p>Support initializing slice fields and nesting structs<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"go\">type ExtraDefault struct {     City   string `default:\"some where\"`     Github string `default:\"${ GITHUB_ADDR }\"` }  type User struct {     Name  string        `default:\"inhere\"`     Age   int           `default:\"300\"`     Extra *ExtraDefault `default:\"\"` \/\/ mark: need init }  optFn := func(opt *structs.InitOptions) {     opt.ParseEnv = true }  obj := &amp;User{} err := structs.InitDefaults(obj, optFn) goutil.PanicErr(err)  dump.P(obj) <\/code><\/pre>\n<p>** Initialization result:**<\/p>\n<pre><code class=\"go\">&amp;structs_test.User {   Name: string(\"inhere\"), #len=6   Age: int(300),   Extra: &amp;structs_test.ExtraDefault {     City: string(\"some where\"), #len=10     Github: string(\"https:\/\/some .... url\"), #len=21   }, }, <\/code><\/pre>\n<h3>Test with Echo Server<\/h3>\n<p>Use <code>testutil.NewEchoServer()<\/code> to quickly create an HTTP echo server. Convenient for testing HTTP requests, responses, etc.<\/p>\n<p><strong>Usage examples:<\/strong><\/p>\n<pre><code class=\"go\"> var testSrvAddr string  func TestMain(m *testing.M) {     s := testutil.NewEchoServer()     defer s.Close()      testSrvAddr = \"http:\/\/\" + s.Listener.Addr().String()     fmt.Println(\"server addr:\", testSrvAddr)      m.Run() }  func TestNewEchoServer(t *testing.T) {     \/\/ can direct request the echo server     r, err := http.Post(testSrvAddr, \"text\/plain\", strings.NewReader(\"hello!\"))     assert.NoErr(t, err)      \/\/ binding response to the testutil.EchoReply     rr := testutil.ParseRespToReply(r)     dump.P(rr)     assert.Eq(t, \"POST\", rr.Method)     assert.Eq(t, \"text\/plain\", rr.ContentType())     assert.Eq(t, \"hello!\", rr.Body) } <\/code><\/pre>\n<h3>v0.6.9 change log<\/h3>\n<blockquote>\n<p>Full changelog <a href=\"https:\/\/github.com\/gookit\/goutil\/compare\/v0.6.8...v0.6.9\" rel=\"noopener noreferrer nofollow\">v0.6.8&#8230;v0.6.9<\/a><\/p>\n<\/blockquote>\n<h4>\u2728 New features<\/h4>\n<ul>\n<li>\n<p>strutil &#8212; Added <code>ToByteSize(),SafeByteSize()<\/code> for converting size string (eg: 5MB) to byte size<\/p>\n<\/li>\n<li>\n<p>strutil has added <code>ParseSizeRange()<\/code> to facilitate and quickly parse string size range expressions eg: <code>200kb~50mb<\/code><\/p>\n<\/li>\n<li>\n<p>strutil &#8212; Added new utility functions: <code>DatetimeNo(), RandWithTpl(), SimpleMatch()<\/code><\/p>\n<\/li>\n<li>\n<p>byteutil &#8212; Add new utility functions: <code>Random()<\/code>, <code>AppendAny()<\/code><\/p>\n<\/li>\n<li>\n<p>fsutil &#8212; Add new utility functions: <code>ReadOrErr()<\/code>, <code>ReadStringOrErr()<\/code><\/p>\n<\/li>\n<li>\n<p>cliutil &#8212; Add new utility functions: <code>Confirm()<\/code>, <code>ReadAsBool()<\/code><\/p>\n<\/li>\n<li>\n<p>errorx &#8212; Add new utility functions <code>Err(), Errf()<\/code> for easy creation of error<\/p>\n<\/li>\n<li>\n<p>structs &#8212; <code>InitDefaults()<\/code> enhanced to support nested structure pointer initialization<\/p>\n<\/li>\n<li>\n<p>structs &#8212; <code>SetValues()<\/code> enhanced to support setting and processing structure pointer values<\/p>\n<\/li>\n<li>\n<p>structs &#8212; Add <code>ToSMap(), TryToSMap(), TryToSMap()<\/code> to convert structure to string map<\/p>\n<\/li>\n<li>\n<p>testutil\/assert new assertion methods <code>NotContainsKey()<\/code>, <code>NotContainsKeys()<\/code><\/p>\n<\/li>\n<li>\n<p>Reflects new utility methods <code>UnexportedValue()<\/code>, <code>SetUnexportedValue()<\/code><\/p>\n<\/li>\n<li>\n<p>maputil new tool functions <code>HasOneKey(), CombineToMap(), TryAnyMap()<\/code><\/p>\n<\/li>\n<li>\n<p>Added utility functions <code>AnyToSlice(), CombineToMap()<\/code> in arrutil<\/p>\n<\/li>\n<li>\n<p>jsonutil has added tool methods <code>IsJSON(), IsJSONFast()<\/code> to check whether it is JSON<\/p>\n<\/li>\n<li>\n<p>\u267b\ufe0f fsutil\/finder file and directory search reconstruction, enhanced functions, more convenient to use<\/p>\n<\/li>\n<li>\n<p>timex new utility functions <code>NowAddSec(), IsDuration(), InRange()<\/code><\/p>\n<\/li>\n<li>\n<p>timex <code>ToDuration()<\/code> enhanced, support unit d, w and long unit hour, min, sec<\/p>\n<\/li>\n<li>\n<p>mathutil new tool methods <code>InRange()<\/code>, <code>OutRange()<\/code>, <code>InUintRange()<\/code><\/p>\n<\/li>\n<li>\n<p>fsutil new tool method <code>RemoveSub()<\/code> to quickly delete subdirectories and files<\/p>\n<\/li>\n<li>\n<p>maputil <code>GetByPath()<\/code> is enhanced to support matching paths similar to <code>top.*.field<\/code> to get values<\/p>\n<\/li>\n<\/ul>\n<h4>? Update adjustments<\/h4>\n<ul>\n<li>\n<p>strutil optimization <code>ToByteSize()<\/code> and <code>GlobMatch()<\/code> logic<\/p>\n<\/li>\n<li>\n<p>struts &#8212; <code>InitDefaults()<\/code> supports initializing non-zero ptr substructure fields<\/p>\n<\/li>\n<li>\n<p>? struts &#8212; <code>InitDefaults()<\/code> To initialize a substructure, the field must be marked with <code>default:\"\"<\/code><\/p>\n<\/li>\n<\/ul>\n<h4>Other adjustments<\/h4>\n<ul>\n<li>\n<p>? doc: README documentation updated, some subpackages added README<\/p>\n<\/li>\n<li>\n<p>\u2705 test: Added and fixed some unit tests<\/p>\n<\/li>\n<li>\n<p>\u2b06\ufe0f dep: update <a href=\"http:\/\/golang.org\/x\" rel=\"noopener noreferrer nofollow\">golang.org\/x<\/a> dependencies to latest version<\/p>\n<\/li>\n<\/ul>\n<h4>Some feature usage examples<\/h4>\n<h3>finder \u6587\u4ef6\u67e5\u627e\u4f7f\u7528<\/h3>\n<p><code>fsutil\/finder<\/code> Provides a simple and fast way to find matching files and directories.<\/p>\n<ul>\n<li>\n<p>Built-in support Name, extension, suffix, prefix, glob, path, etc. include or exclude<\/p>\n<\/li>\n<li>\n<p>Support matching file size, modification time (ModTime) and other extended matching methods<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"go\">ff := finder.NewFinder(\"\/path\/to\/dir\/\").     \/\/ OnlyFindDir(). \/\/ default find files     UseAbsPath().     WithoutDotDir().     WithDirName(\"testdata\").     Include(finder.HumanModTime(\"&lt;10m\")). \/\/ latest 10 minutes, to Now     Include(finder.HumanSize(\"500kb~10mb\")) \/\/ limit file size  \/\/ Find() returns chan, can be for handling for el := range f.Find() {     fmt.Println(el.Path()) } <\/code><\/pre>\n<h3>strutil.ParseSizeRange<\/h3>\n<p>It is easy to parse the string size range to byte size.<\/p>\n<pre><code class=\"go\">opt := &amp;strutil.ParseSizeOpt{}  mix, max, err := strutil.ParseSizeRange(\"1kb~1mb\", opt) goutil.PanicErr(err) fmt.Println(min, max) \/\/ OUTPUT: 1024, 1048576 <\/code><\/pre>\n<p><strong>Examples of supported expression formats:<\/strong><\/p>\n<pre><code>\"1KB~2MB\"       => 1KB to 2MB \"-1KB\"          => &lt;1KB \"~1MB\"          => &lt;1MB \"&lt; 1KB\"         => &lt;1KB \"1KB\"           => >1KB \"1KB~\"          => >1KB \">1KB\"          => >1KB \"+1KB\"          => >1KB <\/code><\/pre>\n<h3>timex.ParseRange()<\/h3>\n<p><code>timex.ParseRange()<\/code> It is easy to quickly parse the relative time size range or keyword into <code>time.Time<\/code><\/p>\n<pre><code class=\"go\">start, end, err := ParseRange(\"-1h~1h\", nil) goutil.PanicErr(err)   fmt.Println(start, end) <\/code><\/pre>\n<p><strong>Examples of supported expression formats:<\/strong><\/p>\n<pre><code>\"-5h~-1h\"           => 5 hours ago to 1 hour ago \"1h~5h\"             => 1 hour after to 5 hours after \"-1h~1h\"            => 1 hour ago to 1 hour after \"-1h\"               => 1 hour ago to feature. eq \"-1h~\" \"-1h~0\"             => 1 hour ago to now. \"&lt; -1h\" OR \"~-1h\"   => 1 hour ago. \"> 1h\" OR \"1h\"      => 1 hour after to feature  \/\/ keyword: now, today, yesterday, tomorrow \"today\"          => today start to today end \"yesterday\"      => yesterday start to yesterday end \"tomorrow\"       => tomorrow start to tomorrow end <\/code><\/pre>\n<h3>More usage<\/h3>\n<p>For more instructions, see Unit tests for <a href=\"https:\/\/github.com\/gookit\/slog\/blob\/master\/README.zh-CN.md\" rel=\"noopener noreferrer nofollow\">README<\/a> and related methods<\/p>\n<blockquote>\n<p><strong>Github<\/strong>: <a href=\"https:\/\/github.com\/gookit\/goutil\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gookit\/goutil<\/a><\/p>\n<\/blockquote>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/746304\/\"> https:\/\/habr.com\/ru\/articles\/746304\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><code>gookit\/goutil<\/code> An extended library of Go&#8217;s common functionality. Contains: number, string, slice\/array, Map, struct, reflection, text, file, error, time and date, test, CLI, command run, system information, formatting, common information acquisition, etc.<\/p>\n<blockquote>\n<p><strong>Github<\/strong>: <a href=\"https:\/\/github.com\/gookit\/goutil\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gookit\/goutil<\/a><\/p>\n<\/blockquote>\n<h3>v0.6.10 change log<\/h3>\n<blockquote>\n<p>Full changelog <a href=\"https:\/\/github.com\/gookit\/goutil\/compare\/v0.6.9...v0.6.10\" rel=\"noopener noreferrer nofollow\">v0.6.9&#8230;v0.6.10<\/a><\/p>\n<\/blockquote>\n<h4>\u2728 New features<\/h4>\n<ul>\n<li>\n<p>\u2728 feat: testutil &#8212; adds a new child package <code>fakeobj<\/code> to create fake objects for testing<\/p>\n<\/li>\n<li>\n<p>\u2728 feat: testutil &#8212; adds a new function NewEchoServer() to start the echo server<\/p>\n<\/li>\n<li>\n<p>\u2728 feat: byteutil &#8212; Buffer adds more useful methods for ease of use<\/p>\n<\/li>\n<li>\n<p>\u2728 feat: dump &#8212; Special handling of custom int, uint type values, will print instructions in String format<\/p>\n<\/li>\n<li>\n<p>\u2728 feat: fsutil &#8212; adds a new function to Glob() quickly list matching files<\/p>\n<\/li>\n<li>\n<p>\u267b\ufe0f feat: httpreq &#8212; Refactoring the built-in HTTP client httpreq logic<\/p>\n<\/li>\n<\/ul>\n<h4>? Update Adjustments<\/h4>\n<ul>\n<li>\n<p>? up: structs &#8212; Update and support InitDefaults() for struct slice fields that are not null<\/p>\n<\/li>\n<li>\n<p>? up: maputil &#8212; <code>SimpleMerge()<\/code> Supports deep merging of map[string]any data<\/p>\n<\/li>\n<\/ul>\n<h4>Other adjustments<\/h4>\n<ul>\n<li>\n<p>\u2705 test: Update some documentation and fix some unit tests<\/p>\n<\/li>\n<li>\n<p>\u2b06\ufe0f dep: Update <a href=\"http:\/\/golang.org\/x\" rel=\"noopener noreferrer nofollow\">golang.org\/x<\/a> depends on the latest version<\/p>\n<\/li>\n<\/ul>\n<h4>Some feature usage examples<\/h4>\n<h3>dump &#8212; prints custom types<\/h3>\n<p>dump &#8212; special handles custom int, uint type values, and will print instructions in String format<\/p>\n<figure class=\"full-width\">\n<div><figcaption>dump custom_type.png<\/figcaption><\/div>\n<\/figure>\n<h3>Initialize the struct<\/h3>\n<ul>\n<li>\n<p>Support for initializing the use of environment variables<\/p>\n<\/li>\n<li>\n<p>Support initializing slice fields and nesting structs<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"go\">type ExtraDefault struct {     City   string `default:\"some where\"`     Github string `default:\"${ GITHUB_ADDR }\"` }  type User struct {     Name  string        `default:\"inhere\"`     Age   int           `default:\"300\"`     Extra *ExtraDefault `default:\"\"` \/\/ mark: need init }  optFn := func(opt *structs.InitOptions) {     opt.ParseEnv = true }  obj := &amp;User{} err := structs.InitDefaults(obj, optFn) goutil.PanicErr(err)  dump.P(obj) <\/code><\/pre>\n<p>** Initialization result:**<\/p>\n<pre><code class=\"go\">&amp;structs_test.User {   Name: string(\"inhere\"), #len=6   Age: int(300),   Extra: &amp;structs_test.ExtraDefault {     City: string(\"some where\"), #len=10     Github: string(\"https:\/\/some .... url\"), #len=21   }, }, <\/code><\/pre>\n<h3>Test with Echo Server<\/h3>\n<p>Use <code>testutil.NewEchoServer()<\/code> to quickly create an HTTP echo server. Convenient for testing HTTP requests, responses, etc.<\/p>\n<p><strong>Usage examples:<\/strong><\/p>\n<pre><code class=\"go\"> var testSrvAddr string  func TestMain(m *testing.M) {     s := testutil.NewEchoServer()     defer s.Close()      testSrvAddr = \"http:\/\/\" + s.Listener.Addr().String()     fmt.Println(\"server addr:\", testSrvAddr)      m.Run() }  func TestNewEchoServer(t *testing.T) {     \/\/ can direct request the echo server     r, err := http.Post(testSrvAddr, \"text\/plain\", strings.NewReader(\"hello!\"))     assert.NoErr(t, err)      \/\/ binding response to the testutil.EchoReply     rr := testutil.ParseRespToReply(r)     dump.P(rr)     assert.Eq(t, \"POST\", rr.Method)     assert.Eq(t, \"text\/plain\", rr.ContentType())     assert.Eq(t, \"hello!\", rr.Body) } <\/code><\/pre>\n<h3>v0.6.9 change log<\/h3>\n<blockquote>\n<p>Full changelog <a href=\"https:\/\/github.com\/gookit\/goutil\/compare\/v0.6.8...v0.6.9\" rel=\"noopener noreferrer nofollow\">v0.6.8&#8230;v0.6.9<\/a><\/p>\n<\/blockquote>\n<h4>\u2728 New features<\/h4>\n<ul>\n<li>\n<p>strutil &#8212; Added <code>ToByteSize(),SafeByteSize()<\/code> for converting size string (eg: 5MB) to byte size<\/p>\n<\/li>\n<li>\n<p>strutil has added <code>ParseSizeRange()<\/code> to facilitate and quickly parse string size range expressions eg: <code>200kb~50mb<\/code><\/p>\n<\/li>\n<li>\n<p>strutil &#8212; Added new utility functions: <code>DatetimeNo(), RandWithTpl(), SimpleMatch()<\/code><\/p>\n<\/li>\n<li>\n<p>byteutil &#8212; Add new utility functions: <code>Random()<\/code>, <code>AppendAny()<\/code><\/p>\n<\/li>\n<li>\n<p>fsutil &#8212; Add new utility functions: <code>ReadOrErr()<\/code>, <code>ReadStringOrErr()<\/code><\/p>\n<\/li>\n<li>\n<p>cliutil &#8212; Add new utility functions: <code>Confirm()<\/code>, <code>ReadAsBool()<\/code><\/p>\n<\/li>\n<li>\n<p>errorx &#8212; Add new utility functions <code>Err(), Errf()<\/code> for easy creation of error<\/p>\n<\/li>\n<li>\n<p>structs &#8212; <code>InitDefaults()<\/code> enhanced to support nested structure pointer initialization<\/p>\n<\/li>\n<li>\n<p>structs &#8212; <code>SetValues()<\/code> enhanced to support setting and processing structure pointer values<\/p>\n<\/li>\n<li>\n<p>structs &#8212; Add <code>ToSMap(), TryToSMap(), TryToSMap()<\/code> to convert structure to string map<\/p>\n<\/li>\n<li>\n<p>testutil\/assert new assertion methods <code>NotContainsKey()<\/code>, <code>NotContainsKeys()<\/code><\/p>\n<\/li>\n<li>\n<p>Reflects new utility methods <code>UnexportedValue()<\/code>, <code>SetUnexportedValue()<\/code><\/p>\n<\/li>\n<li>\n<p>maputil new tool functions <code>HasOneKey(), CombineToMap(), TryAnyMap()<\/code><\/p>\n<\/li>\n<li>\n<p>Added utility functions <code>AnyToSlice(), CombineToMap()<\/code> in arrutil<\/p>\n<\/li>\n<li>\n<p>jsonutil has added tool methods <code>IsJSON(), IsJSONFast()<\/code> to check whether it is JSON<\/p>\n<\/li>\n<li>\n<p>\u267b\ufe0f fsutil\/finder file and directory search reconstruction, enhanced functions, more convenient to use<\/p>\n<\/li>\n<li>\n<p>timex new utility functions <code>NowAddSec(), IsDuration(), InRange()<\/code><\/p>\n<\/li>\n<li>\n<p>timex <code>ToDuration()<\/code> enhanced, support unit d, w and long unit hour, min, sec<\/p>\n<\/li>\n<li>\n<p>mathutil new tool methods <code>InRange()<\/code>, <code>OutRange()<\/code>, <code>InUintRange()<\/code><\/p>\n<\/li>\n<li>\n<p>fsutil new tool method <code>RemoveSub()<\/code> to quickly delete subdirectories and files<\/p>\n<\/li>\n<li>\n<p>maputil <code>GetByPath()<\/code> is enhanced to support matching paths similar to <code>top.*.field<\/code> to get values<\/p>\n<\/li>\n<\/ul>\n<h4>? Update adjustments<\/h4>\n<ul>\n<li>\n<p>strutil optimization <code>ToByteSize()<\/code> and <code>GlobMatch()<\/code> logic<\/p>\n<\/li>\n<li>\n<p>struts &#8212; <code>InitDefaults()<\/code> supports initializing non-zero ptr substructure fields<\/p>\n<\/li>\n<li>\n<p>? struts &#8212; <code>InitDefaults()<\/code> To initialize a substructure, the field must be marked with <code>default:\"\"<\/code><\/p>\n<\/li>\n<\/ul>\n<h4>Other adjustments<\/h4>\n<ul>\n<li>\n<p>? doc: README documentation updated, some subpackages added README<\/p>\n<\/li>\n<li>\n<p>\u2705 test: Added and fixed some unit tests<\/p>\n<\/li>\n<li>\n<p>\u2b06\ufe0f dep: update <a href=\"http:\/\/golang.org\/x\" rel=\"noopener noreferrer nofollow\">golang.org\/x<\/a> dependencies to latest version<\/p>\n<\/li>\n<\/ul>\n<h4>Some feature usage examples<\/h4>\n<h3>finder \u6587\u4ef6\u67e5\u627e\u4f7f\u7528<\/h3>\n<p><code>fsutil\/finder<\/code> Provides a simple and fast way to find matching files and directories.<\/p>\n<ul>\n<li>\n<p>Built-in support Name, extension, suffix, prefix, glob, path, etc. include or exclude<\/p>\n<\/li>\n<li>\n<p>Support matching file size, modification time (ModTime) and other extended matching methods<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"go\">ff := finder.NewFinder(\"\/path\/to\/dir\/\").     \/\/ OnlyFindDir(). \/\/ default find files     UseAbsPath().     WithoutDotDir().     WithDirName(\"testdata\").     Include(finder.HumanModTime(\"&lt;10m\")). \/\/ latest 10 minutes, to Now     Include(finder.HumanSize(\"500kb~10mb\")) \/\/ limit file size  \/\/ Find() returns chan, can be for handling for el := range f.Find() {     fmt.Println(el.Path()) } <\/code><\/pre>\n<h3>strutil.ParseSizeRange<\/h3>\n<p>It is easy to parse the string size range to byte size.<\/p>\n<pre><code class=\"go\">opt := &amp;strutil.ParseSizeOpt{}  mix, max, err := strutil.ParseSizeRange(\"1kb~1mb\", opt) goutil.PanicErr(err) fmt.Println(min, max) \/\/ OUTPUT: 1024, 1048576 <\/code><\/pre>\n<p><strong>Examples of supported expression formats:<\/strong><\/p>\n<pre><code>\"1KB~2MB\"       => 1KB to 2MB \"-1KB\"          => &lt;1KB \"~1MB\"          => &lt;1MB \"&lt; 1KB\"         => &lt;1KB \"1KB\"           => >1KB \"1KB~\"          => >1KB \">1KB\"          => >1KB \"+1KB\"          => >1KB <\/code><\/pre>\n<h3>timex.ParseRange()<\/h3>\n<p><code>timex.ParseRange()<\/code> It is easy to quickly parse the relative time size range or keyword into <code>time.Time<\/code><\/p>\n<pre><code class=\"go\">start, end, err := ParseRange(\"-1h~1h\", nil) goutil.PanicErr(err)   fmt.Println(start, end) <\/code><\/pre>\n<p><strong>Examples of supported expression formats:<\/strong><\/p>\n<pre><code>\"-5h~-1h\"           => 5 hours ago to 1 hour ago \"1h~5h\"             => 1 hour after to 5 hours after \"-1h~1h\"            => 1 hour ago to 1 hour after \"-1h\"               => 1 hour ago to feature. eq \"-1h~\" \"-1h~0\"             => 1 hour ago to now. \"&lt; -1h\" OR \"~-1h\"   => 1 hour ago. \"> 1h\" OR \"1h\"      => 1 hour after to feature  \/\/ keyword: now, today, yesterday, tomorrow \"today\"          => today start to today end \"yesterday\"      => yesterday start to yesterday end \"tomorrow\"       => tomorrow start to tomorrow end <\/code><\/pre>\n<h3>More usage<\/h3>\n<p>For more instructions, see Unit tests for <a href=\"https:\/\/github.com\/gookit\/slog\/blob\/master\/README.zh-CN.md\" rel=\"noopener noreferrer nofollow\">README<\/a> and related methods<\/p>\n<blockquote>\n<p><strong>Github<\/strong>: <a href=\"https:\/\/github.com\/gookit\/goutil\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gookit\/goutil<\/a><\/p>\n<\/blockquote>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/746304\/\"> https:\/\/habr.com\/ru\/articles\/746304\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-393218","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/393218","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=393218"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/393218\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=393218"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=393218"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=393218"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}