在 GitHub 上编辑此页面

实验定义

The @experimental 注释允许定义一个 API,该 API 不保证向后二进制或源代码兼容性。此注释可以放置在术语或类型定义上。

对实验性定义的引用

实验性定义只能在实验性范围内引用。实验性范围定义如下

  1. 实验性 defvalvargiventype 的 RHS 是一个实验性范围。示例

    Example 1
    import scala.annotation.experimental
    
    @experimental
    def x = ()
    
    def d1 = x // error: value x is marked @experimental and therefore ...
    @experimental def d2 = x
    
    val v1 = x // error: value x is marked @experimental and therefore ...
    @experimental val v2 = x
    
    var vr1 = x // error: value x is marked @experimental and therefore ...
    @experimental var vr2 = x
    
    lazy val lv1 = x // error: value x is marked @experimental and therefore ...
    @experimental lazy val lv2 = x
    
    Example 2
    import scala.annotation.experimental
    
    @experimental
    val x = ()
    
    @experimental
    def f() = ()
    
    @experimental
    object X:
      def fx() = 1
    
    def test1: Unit =
      f() // error: def f is marked @experimental and therefore ...
      x // error: value x is marked @experimental and therefore ...
      X.fx() // error: object X is marked @experimental and therefore ...
      import X.fx
      fx() // error: object X is marked @experimental and therefore ...
    
    @experimental
    def test2: Unit =
      // references to f, x and X are ok because `test2` is experimental
      f()
      x
      X.fx()
      import X.fx
      fx()
    
    Example 3
    import scala.annotation.experimental
    
    @experimental type E
    
    type A = E // error type E is marked @experimental and therefore ...
    @experimental type B = E
    
    Example 4
    import scala.annotation.experimental
    
    @experimental class A
    @experimental type X
    @experimental type Y = Int
    @experimental opaque type Z = Int
    
    def test: Unit =
      new A // error: class A is marked @experimental and therefore ...
      val i0: A = ??? // error: class A is marked @experimental and therefore ...
      val i1: X = ??? // error: type X is marked @experimental and therefore ...
      val i2: Y = ??? // error: type Y is marked @experimental and therefore ...
      val i2: Z = ??? // error: type Y is marked @experimental and therefore ...
      ()
    
    Example 5
    @experimental
    trait ExpSAM {
      def foo(x: Int): Int
    }
    def bar(f: ExpSAM): Unit = {} // error: error form rule 2
    
    def test: Unit =
      bar(x => x) // error: reference to experimental SAM
      ()
    
  2. 实验性 defvalvargiventype 的签名,或 classtrait 的构造函数是实验性范围。示例

    示例 1
    import scala.annotation.experimental
    
    @experimental def x = 2
    @experimental class A
    @experimental type X
    @experimental type Y = Int
    @experimental opaque type Z = Int
    
    def test1(
      p1: A, // error: class A is marked @experimental and therefore ...
      p2: List[A], // error: class A is marked @experimental and therefore ...
      p3: X, // error: type X is marked @experimental and therefore ...
      p4: Y, // error: type Y is marked @experimental and therefore ...
      p5: Z, // error: type Z is marked @experimental and therefore ...
      p6: Any = x // error: def x is marked @experimental and therefore ...
    ): A = ??? // error: class A is marked @experimental and therefore ...
    
    @experimental def test2(
      p1: A,
      p2: List[A],
      p3: X,
      p4: Y,
      p5: Z,
      p6: Any = x
    ): A = ???
    
    class Test1(
      p1: A, // error
      p2: List[A], // error
      p3: X, // error
      p4: Y, // error
      p5: Z, // error
      p6: Any = x // error
    ) {}
    
    @experimental class Test2(
      p1: A,
      p2: List[A],
      p3: X,
      p4: Y,
      p5: Z,
      p6: Any = x
    ) {}
    
    trait Test1(
      p1: A, // error
      p2: List[A], // error
      p3: X, // error
      p4: Y, // error
      p5: Z, // error
      p6: Any = x // error
    ) {}
    
    @experimental trait Test2(
      p1: A,
      p2: List[A],
      p3: X,
      p4: Y,
      p5: Z,
      p6: Any = x
    ) {}
    
  3. 实验性 classtraitobjectextends 子句是一个实验性范围。示例

    示例 1
    import scala.annotation.experimental
    
    @experimental def x = 2
    
    @experimental class A1(x: Any)
    class A2(x: Any)
    
    
    @experimental class B1 extends A1(1)
    class B2 extends A1(1) // error: class A1 is marked @experimental and therefore marked @experimental and therefore ...
    
    @experimental class C1 extends A2(x)
    class C2 extends A2(x) // error def x is marked @experimental and therefore
    
  4. 实验性 classtraitobject 的主体是一个实验性范围。示例

    示例 1
    import scala.annotation.experimental
    
    @experimental def x = 2
    
    @experimental class A {
      def f = x // ok because A is experimental
    }
    
    @experimental class B {
      def f = x // ok because A is experimental
    }
    
    @experimental object C {
      def f = x // ok because A is experimental
    }
    
    @experimental class D {
      def f = {
        object B {
          x // ok because A is experimental
        }
      }
    }
    
  5. 实验性定义的注释位于实验性范围内。示例

    示例 1
    import scala.annotation.experimental
    
    @experimental class myExperimentalAnnot extends scala.annotation.Annotation
    
    @myExperimentalAnnot // error
    def test: Unit = ()
    
    @experimental
    @myExperimentalAnnot
    def test: Unit = ()
    
  6. 使用 NightlySnapshot 版本的编译器编译的任何代码都被视为处于实验性范围内。可以使用 -Yno-experimental 编译器标志禁用它并作为正式版本运行。

在任何其他情况下,对实验性定义的引用都会导致编译错误。

实验性覆盖

对于覆盖成员 M 和被覆盖成员 O,如果 O 不是实验性的,那么 M 必须是非实验性的。

这确保了我们不会出现意外的二进制不兼容性,例如以下更改。

class A:
  def f: Any = 1
class B extends A:
-  @experimental def f: Int = 2

测试框架

测试可以定义为实验性的。测试框架可以使用反射执行测试,即使它们在实验性类、对象或方法中。示例

示例 1

接触实验性 API 的测试可以按如下方式编写

import scala.annotation.experimental

@experimental def x = 2

class MyTests {
  /*@Test*/ def test1 = x // error
  @experimental /*@Test*/ def test2 = x
}

@experimental
class MyExperimentalTests {
  /*@Test*/ def test1 = x
  /*@Test*/ def test2 = x
}

-experimental 编译器标志

此标志允许在项目中使用任何实验性语言特性。它通过向所有顶级定义添加 @experimental 注解来实现这一点。因此,依赖项目也必须是实验性的。