在 Scala 或其他 JVM 语言中,哪种类型声明最接近 C# 或 C++ 中泛型类中嵌套的类型声明?

问题描述 投票:0回答:1

(这是Scala版本,Rust版本请参见在Rust中,哪种类型声明最接近C#或C++中泛型类中嵌套的类型声明?

在用 C# 或 C++ 编写严重依赖泛型/模板的库时,我经常使用的一个技巧是声明几个使用与静态类下的嵌套类型相同的泛型类型参数的结构。

例如这些声明(以 C# 为例):

    public struct Gen1<T1, T2, T3>
    {
    }

    public struct Gen2<T1, T2, T3>
    {
    }

在功能上等同于:

    public static class Ts<T1, T2, T3>
    {
        public struct Gen1
        {
        }

        public struct Gen2
        {
        }
    }

即,Ts.Gen1被编译器转换为一个专门的类,具有自己的静态成员。 Ts 和 Ts 成为 2 个不同的类,除了名称之外没有任何共享。

这与具有类型擦除功能的 JVM 编译器不同,后者在编译期间会删除类型参数。因此,翻译为 Java 的相同静态嵌套类声明只有 1 种类型,并且必须在没有类型参数的情况下进行初始化。

据我所知,没有其他 JVM 语言超越了这个限制(即,Kotlin 编译器不支持专门化像 C#/C++ 这样的泛型类型,Scala 编译器没有

object
类型的静态声明和模板/泛型类型参数) )。事实上,大多数其他语言没有类似的抽象(唯一的例外是 LEAN4,其中静态泛型类成为一个部分:https://lean-lang.org/lean4/doc/sections.html)。

我正在寻找 Scala/Kotlin 类型系统的最小扩展,可以逐行重现这种抽象。鉴于 Scala 具有路径依赖类型和 GADT,它将是我的首选。但我该怎么做呢?

(无需编译器插件实现此目的的一种方法是引入类型相等公理,我不知道如何做到这一点,但如果您回答在带有点演算的 Scala 3 中,如何扩展 2 个路径依赖类型的相等性对于明显的情况?,应该很容易将这个问题的解决方案作为特殊情况包括在内)

scala templates generics static
1个回答
0
投票

我可以想到两种在 Scala 中实现这一点的方法。请尝试以下并检查是否有帮助:

  1. 键入类或特征中的成员

     object MyObject {
         trait Base[T1, T2, T3] {
             type Gen1
             type Gen2
         }
    
         class Implementation[T1, T2, T3] extends Base[T1, T2, T3] {
             type Gen1 = (T1, T2, T3) 
             type Gen2 = (T1, T2, T3)
         }
    
         def create[T1, T2, T3]: Implementation[T1, T2, T3] = new Implementation[T1, T2, T3]
     }   
    
    
     //USAGE:
    
     val instance = MyObject.create[Int, String, Double]
     val gen1: instance.Gen1 = (42, "example", 3.14)
     println(gen1)
     val gen2: instance.Gen2 = (42, "example", 3.14)
     println(gen2)
    
  2. 使用绝对路径的类型:

    object MyObject {
        class Ts[T1, T2, T3] {
            class Gen1 {
                def info(): String = s"Gen1 with T1: $T1, T2: $T2, T3: $T3"
            }
    
            class Gen2 {
                def info(): String = s"Gen2 with T1: $T1, T2: $T2, T3: $T3"
            }
       }   
    }
    
    //USAGE:
    val instance = new MyObject[Int, String, Double]
    val gen1Instance = new instance.Gen1
    println(gen1Instance.info())
    val gen2Instance = new instance.Gen2
    println(gen2Instance.info())
    
© www.soinside.com 2019 - 2024. All rights reserved.