duke-git / lancet

A comprehensive, efficient, and reusable util function library of Go.
https://www.golancet.cn/en/
MIT License
4.7k stars 466 forks source link

建议支持只导入一个包名,就可以使用所有函数的方式 #219

Open CcccFz opened 6 months ago

CcccFz commented 6 months ago

如: import "github.com/duke-git/lancet/v2 便可以通过lancet.XXX()的方式使用到所有函数

否则,若大量使用到lancet各包中的函数时,代码中可能会出现如下情况

import (
  "github.com/duke-git/lancet/v2/xx1`
  "github.com/duke-git/lancet/v2/xx2`
  "github.com/duke-git/lancet/v2/xx3`
  ...
)

这样加重了使用负担,每使用一个函数都会去查看是属于哪个子包下的函数,且容易造成和其它包的包名冲突,不得不给包名起导入别名

若在意编译了多余的不使用的子代码包(比如部分用户可能只会用到个别函数,却编译了整个包),可以2种方式都同时支持。但个人觉得微乎其微

duke-git commented 6 months ago

入别名

@CcccFz lancet中有很多重名方法(例如slice/filter, maputil/filter), package的作用一是代码复用,二是做命名空间。go不支持命名空间语法。兼容性很重要,2种方式都需要支持。如果所有方法都在一个lancet包下,需要导入所有对应的子包,然后定义对应方法的包全局变量。针对重名方法还要重新命名。代码复杂度增加,维护困难,投入产出比低。

duke-git commented 2 months ago

This issue requires us to be able to access all functions in the Lancet library using the lancet.XXX() syntax, rather than importing numerous corresponding packages. I would like to discuss the necessity and feasibility of implementing this feature.

I have thought of a solution to avoid method name conflicts, as described below:

Namespace injection: Define a lancet package within the Lancet library and inject different namespaces by exporting a unified-named object or struct instance. For example, we could export lancet.StrUtil and lancet.Slice as unified-named objects. Users could then access these via different namespace objects, like below code snap:


package lancet

import (
    "github.com/duke-git/lancet/v2/strutil"
    "github.com/duke-git/lancet/v2/slice"

)

var StrUtil = struct {
    Reverse func(s string) string
}{
    Reverse: strutil.Reverse,
}

// compile error: function type must have no type parameters
var Slice = struct {
    Filter func[T any](slice []T, predicate func(index int, item T) bool) []T
}{
    Filter: slice.Filter,
}

Users would use it as follows:


package main

import (
    "github.com/duke-git/lancet/v2"

)

func main() {
    s := "abc"

    rs := lancet.StrUtil.Reverse(s)

    fmt.Println(rs)
}

However, there is a limitation: this approach cannot be applied to generic functions. see the compile error for slice struct. Do you guys or anyone else have any ideas on how to address this issue? @cannian1 @donutloop

cannian1 commented 2 months ago

I don’t think it’s a good idea to support this requirement. On the one hand, users can encapsulate a toolkit themselves to wrap commonly used lancet utility functions. On the other hand, if we are to support this feature, I believe it’s better to use the package name as a prefix for the function, like this:

func SliceUtilCount[T comparable](sli []T, item T) int {
    return slice.Count(sli, item)
}

IDE can provide corresponding prompts after the user has entered enough information.

duke-git commented 2 months ago

I don’t think it’s a good idea to support this requirement. On the one hand, users can encapsulate a toolkit themselves to wrap commonly used lancet utility functions. On the other hand, if we are to support this feature, I believe it’s better to use the package name as a prefix for the function, like this:

func SliceUtilCount[T comparable](sli []T, item T) int {
  return slice.Count(sli, item)
}

IDE can provide corresponding prompts after the user has entered enough information.

If we choose to use the package name as a prefix for function names and then create proxy functions, I'm afraid it will lead to a lot of redundancy since we need to create proxy functions for all the existing functions. None of the current solution can elegantly solve this issue.

Perhaps you are right; we may not need to support this requirement.