V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
jeesk
V2EX  ›  程序员

Java 的泛型能够向 golang 一样, T 可以表示多个类型?

  •  
  •   jeesk · 2022-12-25 00:49:47 +08:00 · 4322 次点击
    这是一个创建于 482 天前的主题,其中的信息可能已经有所发展或是发生改变。
    func SumIntsOrFloats[K comparable, V int | float64](m map[K]V) V {
        var s V
        for _, v := range m {
            s += v
        }
        return s
    }
    

    比如上面这段代码? v 表示的是两种类型。 但是 java/kotlin 里面好像只有上限和下限。

        fun <T : File> getString(uri: T): T {
            return uri
        }
    

    kotlin 里面的 T ,类型只有一种,感觉是真的不方便? 各位大神,kotlin 或者 java 有没有其他的写法支持多种类型?

    30 条回复    2022-12-27 08:38:50 +08:00
    Rocketer
        1
    Rocketer  
       2022-12-25 01:07:46 +08:00 via iPhone
    只有弱类型语言才可能这样,比如 TypeScript 也可以。

    强类型语言的优势就是强类型,不方便只是你不习惯,并不是弱点。
    jeesk
        2
    jeesk  
    OP
       2022-12-25 01:08:55 +08:00
    @Rocketer golang 是个例外?
    Trim21
        3
    Trim21  
       2022-12-25 01:34:38 +08:00
    @jeesk #2

    golang 的泛型也不一定能表示多个类型,你的例子是基础类型,用到的也只是 + ,所以可以这样写。

    但如果换成 struct 的话就不行了


    type T1 struct {
    }

    func (t T1) Close() error {
    return nil
    }

    type T2 struct {
    }

    func (t T2) Close() error {
    return nil
    }

    这个可以编译

    var _ io.Closer = T1{}
    var _ io.Closer = T2{}


    但这个泛型函数没法编译

    func CanNotCompile[T T1 | T2](t T) error {
    return t.Close()
    }
    TWorldIsNButThis
        4
    TWorldIsNButThis  
       2022-12-25 01:34:49 +08:00
    overload
    GeruzoniAnsasu
        5
    GeruzoniAnsasu  
       2022-12-25 02:37:15 +08:00
    @Trim21 可以绕:

    type typeProxy interface {
    Close() error
    }

    func CanCompile[T T1 | T2](t T) error {
    return any(t).(typeProxy).Close()
    }

    CanCompile(T3{}) // 拒绝编译


    --------

    java 的泛型系统的「类型限制」( constraint )只能指定类型继承链上的上下界,泛型容器或泛型方法仅仅是把对象的类型自动向上转换而已,因此不可能指定不在同一继承链上的两个任意类型的组合类型( T | U ),设想 (T|U) t; t.Method(); 此时 t 的类型只能协变为 Object ,而 Object 不会有 Method()方法。

    这跟强弱类型语言没什么关系,跟泛型系统的实现和设计有关,只能说,java 就这样,你想实现接近的效果,有非泛型的写法( instanceof )
    Leviathann
        6
    Leviathann  
       2022-12-25 02:54:26 +08:00
    java 没有或类型,要表达同一个意思,就是用重载
    pennai
        7
    pennai  
       2022-12-25 04:09:42 +08:00
    c++可以
    kakach
        8
    kakach  
       2022-12-25 06:50:06 +08:00 via Android   ❤️ 1
    BBCCBB
        9
    BBCCBB  
       2022-12-25 09:27:38 +08:00
    interface/abstract, 比如(Number t), t 可以传 int, float, double, long 等, 不过必须子类实现父类才行,,
    不能像 go 这样直接指定多个.
    jeesk
        10
    jeesk  
    OP
       2022-12-25 09:30:07 +08:00 via Android
    @GeruzoniAnsasu 所以 java 的泛型是假的, 语法糖😅
    ZSeptember
        11
    ZSeptember  
       2022-12-25 09:35:01 +08:00   ❤️ 3
    不是一句假的这么简单。。

    泛型有很多种实现方式,CPP 的基于模板的,Go 也类似基于模板的,Java 是基于类型擦除的,各有优劣。

    而且,不支持 union type ,只是语言层的问题,和泛型实现没什么关系,有需要的话,Java 也可以支持。
    coala
        12
    coala  
       2022-12-25 10:52:51 +08:00
    Java 的泛型是假的. class 文件反编译后你就看到了,new ArrayList<String>() 反编译后是 new ArrayList(), 其他语言的是怎么实现的不清楚, 但是 Java 算是比较取巧的方式吧, 大概只有编译时检查泛型, 实际上最下面还是 object
    iseki
        13
    iseki  
       2022-12-25 10:54:04 +08:00 via Android
    不支持联合类型,和泛型其实没太大关系,你看 ts 不用泛型也能联合类型。语言设计问题,可能和 Java 是名义类型有点关系,也许联合类型这种情况下不太好实现?
    iseki
        14
    iseki  
       2022-12-25 10:57:07 +08:00 via Android
    至于类型擦除…Java 这种实现的好处是代码不膨胀,和旧的兼容,运行时也没额外消耗,坏处就是运行时不一定能拿到泛型信息
    coala
        15
    coala  
       2022-12-25 11:01:28 +08:00
    感觉这就和茴的几种写法一样.. 泛型是为了什么呢, 如果是为了统一类型, 一个 ArrayList 你说允许有两种类型. 我这写了几年 Java 的脑回路反而有点不适, 无法就是在灵活和规整直接做取舍
    jeesk
        16
    jeesk  
    OP
       2022-12-25 11:04:46 +08:00 via Android
    @coala 少写代码。 比如别人的接口参数就是 object 类型, 支持的就是 string 或者 int 类型,我要限制类型, 这个时候我要写 2 个方法分别是 stringh 和 int 的类型, 少写点代码就少写。
    jeesk
        17
    jeesk  
    OP
       2022-12-25 11:06:34 +08:00 via Android
    @coala 你写写其它语言就知道了,java 太不灵活了, 对于个人项目重构成本高。
    iseki
        18
    iseki  
       2022-12-25 11:07:46 +08:00 via Android
    @jeesk 我觉得你举的这个例子用 union type 不太好,overload 更合适。你写了个 string | int ,里面还是要 is string is int 分别去处理
    jeesk
        19
    jeesk  
    OP
       2022-12-25 11:09:16 +08:00 via Android
    @iseki 不用处理啦。别人的接口就是 object 类型。
    iseki
        20
    iseki  
       2022-12-25 11:10:15 +08:00 via Android
    噢,我懂了,你是额外在人家的接口上加了个约束
    jeesk
        21
    jeesk  
    OP
       2022-12-25 11:10:50 +08:00 via Android
    @iseki 重载也行, 不过能像 golang 一样能省就好了。
    coala
        22
    coala  
       2022-12-25 11:49:45 +08:00
    @jeesk 第一次写 node.js 的时候, 当时实现了一个简单 WebSocket Server, node.js 居然只用 1 个文件 20 多行代码就搞定了, Java 干这个事得定义了好几个对象, 几个文件配合干, 代码很容易一大片。 对我来说非常震撼。

    Java 现在只在编译时检查一个泛型, 看上去实现检查 2 个泛型也不是什么难事, 兼容旧版这种理由我是不信的, 编译时能检查一个也能检查两个 , 反正是 "假泛型"。 我更倾向于作者就是觉得只允许一个类型更好一点。 像 Python 强制 4 个空格的语法, 咱也不敢骂。

    没有泛型好, 还是只有一种类型好, 还是支持多种类型好, 真的有答案吗?
    jeesk
        23
    jeesk  
    OP
       2022-12-25 12:03:46 +08:00
    @coala java 也能呀, 都写在一个文件里面不是问题。
    coala
        24
    coala  
       2022-12-25 12:19:49 +08:00
    @iseki 是的, 我也觉得 Golang 更好一点, Java 一般
    iseki
        25
    iseki  
       2022-12-25 12:24:38 +08:00
    @coala 不不不,我觉得 Go 是一个设计的很差的语言,Java 太罗嗦,我选择 Kotlin (洗手)
    coala
        26
    coala  
       2022-12-25 12:36:18 +08:00
    @iseki 2333, 圈错了, Sorry...
    Huelse
        27
    Huelse  
       2022-12-25 13:51:41 +08:00
    可能 Scala3 更符合你的需求,如 Intersection Types, Union Types 等等 https://dotty.epfl.ch/
    lisongeee
        28
    lisongeee  
       2022-12-25 13:55:58 +08:00
    kotlin 可以通过密封类实现联合类型类似效果,但是不如 typescript 灵活
    hhjswf
        29
    hhjswf  
       2022-12-26 14:38:29 +08:00
    @coala 你不会是手撸的吧? Java 用现成的轮子基于注解还是可以的
    netabare
        30
    netabare  
       2022-12-27 08:38:50 +08:00 via Android   ❤️ 1
    这个是 sum type ,typescript 里面有不错的支持。kotlin 和 java 都没有,得用 scala ,不然就是纯 fp 的 ocaml 、haskell 之类的语言才有了。

    sealed class 模拟的问题在于不能用再已有的类型上,必须手写一层例如 IntWrapper 、StringWrapper 之类的层来套着,对数据互转很不方便。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1154 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 18:19 · PVG 02:19 · LAX 11:19 · JFK 14:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.