一种兼容性更好的 Go 泛型设计 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
Kulics

一种兼容性更好的 Go 泛型设计

  •  
  •   Kulics
    kulics Jan 9, 2020 5392 views
    This topic created in 2303 days ago, the information mentioned may be changed or developed.

    最近我在我设计的 Lite 语言中探索了一种新的泛型语法,因为 Lite 从 Go 中借鉴了不少语法,所以这种泛型语法对于 Go 可能也有一定的参考价值。

    identifier<T>这种最主流的语法比较大的问题是与比较操作符冲突,同时也与位操作符冲突,因此我不赞同这种设计。

    Scala的identifier[T]语法比前面的语法有更好的观感,但解决了上面的冲突之后又与索引语法identifier[index]产生了新的冲突, 为此Scala的索引语法改为了identifier(index)。这对于已经采用[]作为索引的语言来说效果也不算很好。

    在 Go 的草案中,声明泛型使用(typeT)的方式,这不会造成冲突,因为type是关键字,但是调用的时候依然需要编译器进行更多判断才能解决identifier(type)(params)的冲突问题,虽然它比以上的方案都好,但仍然不能让我满意。

    偶然的机会让我想起了OC中方法调用的特殊语法,这给了我一种新语法的灵感。

    如果我们将标识符和泛型组成一个整体,一起放入 [] 如何?

    我们可以得到这个语法 [identifier T], 这个语法不会与索引语法产生冲突,因为它必然存在至少两个元素,中间使用空格隔开。

    当存在多个泛型时,我们可以这样写 [identifier T, V],同样不会与现有的语法产生冲突。

    将这个语法代入 Go 中,我们可以得到下面的例子。

    E.g.

    type [Item T] struct { Value T } func (item [Item T]) Print() { println(item.Value) } func [TestGenerics T, V]() { a := [Item T]{} a.Print() b := [Item V]{} b.Print() } func main() { [TestGenerics int, string]() } 

    这看起来非常清晰。

    使用 [] 的另一个好处是,与 Go 原本的 Slice 和 Map 语法有一定传承性,不会造成割裂感。

    []int -> [slice int] map[string]int -> [map string, int] 

    我们可以造一个更复杂的例子

    var a map[int][]map[string]map[string][]string var b [map int, [slice [map string, [map string, [slice string]]]]] 

    这个例子依然能保持比较清晰的效果,同时对编译造成的影响很小。

    我已经在 Lite 中实现并测试了这个语法,在 Lite 中效果很好,没有产生歧义。

    这个设计也许值得引起讨论,我已经在 github 上提交了一个 issue,欢迎一起来讨论。

    https://github.com/golang/go/issues/36457

    23 replies    2020-01-09 22:09:13 +08:00
    codehz
        1
    codehz  
       Jan 9, 2020
    L i s p
    直接说 S-Exp 就好了(
    codehz
        2
    codehz  
       Jan 9, 2020
    甚至逗号都不需要,直接用空格区分多参数(
    不过多参数是万恶之源,应该柯里化一下,做成 * -> * -> * 的模式(
    Kulics
        3
    Kulics  
    OP
       Jan 9, 2020
    @codehz hhhhhhh 站在巨人的肩膀上
    dodo2012
        4
    dodo2012  
       Jan 9, 2020
    var b [map int, [slice [map string, [map string, [slice string]]]]]

    这个套的眼花了都,不觉得有多清晰,使用<T>的方式,更多是大家都是这样用的,更熟悉,
    IsaacYoung
        5
    IsaacYoung  
       Jan 9, 2020
    <>
    Kulics
        6
    Kulics  
    OP
       Jan 9, 2020
    @dodo2012
    var b map<int, slice<map<string, map<string, slice<string>>>>>
    var b [map int, [slice [map string, [map string, [slice string]]]]]

    相比之下,我还是觉得比<T>的方式清晰一些。
    liuguang
        7
    liuguang  
       Jan 9, 2020
    换汤不换药
    thisisgpy
        8
    thisisgpy  
       Jan 9, 2020
    楼主你的 Lite 语言,运算符设计的太复杂了
    kifile
        9
    kifile  
       Jan 9, 2020
    觉得只是 [] 比 <> 占的显示控件笑了,[doge]
    kifile
        10
    kifile  
       Jan 9, 2020
    显示空间小了
    hantsy
        11
    hantsy  
       Jan 9, 2020
    用 Java 多了,还是感觉<>好
    inhzus
        12
    inhzus  
       Jan 9, 2020 via Android
    可能是我 go 写太多了吗?我觉得楼主最后举的例子 go 的例子看起来挺显然的…
    imnaive
        13
    imnaive  
       Jan 9, 2020
    这个不是设计,是一种语法吧
    fcten
        14
    fcten  
       Jan 9, 2020
    "identifier<T> 这种最主流的语法比较大的问题是与比较操作符冲突,同时也与位操作符冲突,因此我不赞同这种设计。"

    这个前提就不对。操作符和类型声明出现的位置完全不一样,在解析成 AST 之前就可以区分清楚了,对于编译器来说是属于比较容易解析的语法。
    就比如括号 ( ) ,非常常见的符号,并且有多种语法,也没有冲突的问题。

    语法首先是为语义服务的。先设计功能,再设计语法。所以,到底冲不冲突,最终是要看该语法被用来支持哪些语义。用其它语言的泛型设计来推断 Go 的语法本身也是有问题的。
    cyspy
        15
    cyspy  
       Jan 9, 2020
    scala 没有索引语法,只是 apply 函数而已
    Kulics
        16
    Kulics  
    OP
       Jan 9, 2020
    @thisisgpy 的确是复杂,一开始特性少还好,后来特性越来越完备,复杂性就升上去了。只要功能多,复杂是必然的了。
    Kulics
        17
    Kulics  
    OP
       Jan 9, 2020
    @kifile 主要还是类似 s-expr 的语法比<T>形式的界限看起来清晰一些,把[]换成<>其实也会比原来的看起来清晰。
    Kulics
        18
    Kulics  
    OP
       Jan 9, 2020
    @hantsy 可是不适合 go 啊,go 草案已经排斥了<>。不然也不会有机会来讨论这个语法。
    Kulics
        19
    Kulics  
    OP
       Jan 9, 2020
    @imnaive 这么说也对,语法设计。
    Kulics
        20
    Kulics  
    OP
       Jan 9, 2020
    @fcten 曾经我也是这么想,直到后来自己写了个编译器才发现问题。
    Kulics
        21
    Kulics  
    OP
       Jan 9, 2020
    @cyspy 你说的没错,的确不适合已经用[]去处理索引的语言。
    saltsugar
        22
    saltsugar  
       Jan 9, 2020
    第一眼看过去就是 lisp 啊,不过确实挺好。
    对我这个对 go 语法还有点陌生的人来说,看的轻松。
    saltsugar
        23
    saltsugar  
       Jan 9, 2020
    看惯了 c/c++, 现在看 go 总是要转换一下思维。
    现在特别赞同傻白甜设计。
    About     Help     Advertise     Blog     API     FAQ     Solana     898 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 55ms UTC 22:41 PVG 06:41 LAX 15:41 JFK 18:41
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86