smallnest / gitalk

gitalk for colobu
19 stars 0 forks source link

Go泛型不支持泛型方法,这是一个悲伤的故事 #219

Open utterances-bot opened 2 years ago

utterances-bot commented 2 years ago

Go泛型不支持泛型方法,这是一个悲伤的故事

根据Go 泛型提案的描述,Go不支持泛型方法:No parameterized methods。主要原因Go泛型的处理是在编译的时候实现的,泛型方法在编译的时候,如果没有上下文的分析推断,很难判断泛型方案该如何实例化,甚至判断不了,导致目前(Go 1.18)Go实现中不支

https://colobu.com/2021/12/22/no-parameterized-methods/

seekdoor commented 2 years ago

错字

这也是促进哦把这几天看到的case总结的原因。

r如果是熟悉其它编程语言,

wdvxdr1123 commented 2 years ago

有一点点让人欣慰的是,Ian Lance Taylor和Ian Lance Taylor并没有把话说绝

有处笔误,应为 Ian Lance Taylor和Robert Griesemer

laizy commented 2 years ago

第一次试用也发现了这个限制,怎么也绕不开。我感觉Facilitator模式也没解决问题,只是把问题甩给了All函数:

func (q *Querier[T]) All(ctx context.Context) ([]T, error) {
    // implementation
       // 除非支持特化,否则这里怎么实现能够返回一个任意的[]T??
}
dingyaguang117 commented 1 year ago

"泛型signleflight" -> "泛型singleflight"

ireina7 commented 1 year ago

其实可以用类似Haskell或者Rust的newtype pattern来凑活,而且由于interface不是单纯的类型类,有可能要当类似rust的trait object来用,所以这个问题其实不好解决。当你需要给一个已有的类型用复杂的带泛型的方法的时候,就把它“lift“到另外一个new type上,通过newtype的泛型来调用泛型方法。当你需要在一个对象上用多个不同的泛型,只需要类型转换一下(大多数情况下是指针,损耗不大)。

type Logic[T any] int

func (self *Logic[T]) sum(xs []T, ops Monoid[T]) T {
    ans := ops.Zero()
    for _, x := range xs {
        ans = ops.Add(ans, x)
    }
    return ans
}
func TestCast() {
    origin_obj := 0
    logic := &origin_obj
    // sum := (*Logic[int])(logic).sum
    (*Logic[int])(logic).sum([]int{1, 2, 3}, new(MonoidInt))
    (*Logic[string])(logic).sum([]string{"fst", "snd"}, new(MonoidString))
}
jxffly commented 1 year ago

想的我头疼 只能换一种方法泛型了

var ( OK = Code(0, "success") IllegalArgument = Code(100400, "illegal argument") )

type ResponseCode struct { Code int json:"code" Msg string json:"msg" }

func (code *ResponseCode)[T any] ToRsp() AppResponse[T anm] { return Create(code.Code, code.Msg) }

func Code(code int, msg string) *ResponseCode { return &ResponseCode{code, msg} }

jxffly commented 1 year ago

func ToRsp[T any](code *ResponseCode) AppResponse[T] { return Create(code.Code, code.Msg) }

rainydew commented 1 year ago

既然举了db的例子,这么做有个非常大的问题是违背了单例模式。比如想生成多个db但底层是一个实例就相当难做(因为每个泛型结构会被当成一个新的实例)。或者也可以投机取巧,在实例的工厂方法里增加一个成员,这个成员是指向底层操作数据库的单例对象的指针。为了保护单例,可以把这个对象做成一个私有接口(含private()空方法就行),别人在包外无法实现。但这样复杂度就相当高了

Anthony-Dong commented 2 months ago

真的坑,没有这个能力很多地方做起来太过于麻烦了!