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

2022-12-25 00:49:47 +08:00
 jeesk
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 有没有其他的写法支持多种类型?

4603 次点击
所在节点    程序员
30 条回复
Rocketer
2022-12-25 01:07:46 +08:00
只有弱类型语言才可能这样,比如 TypeScript 也可以。

强类型语言的优势就是强类型,不方便只是你不习惯,并不是弱点。
jeesk
2022-12-25 01:08:55 +08:00
@Rocketer golang 是个例外?
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
2022-12-25 01:34:49 +08:00
overload
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
2022-12-25 02:54:26 +08:00
java 没有或类型,要表达同一个意思,就是用重载
pennai
2022-12-25 04:09:42 +08:00
c++可以
kakach
2022-12-25 06:50:06 +08:00
BBCCBB
2022-12-25 09:27:38 +08:00
interface/abstract, 比如(Number t), t 可以传 int, float, double, long 等, 不过必须子类实现父类才行,,
不能像 go 这样直接指定多个.
jeesk
2022-12-25 09:30:07 +08:00
@GeruzoniAnsasu 所以 java 的泛型是假的, 语法糖😅
ZSeptember
2022-12-25 09:35:01 +08:00
不是一句假的这么简单。。

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

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

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/904511

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX