【问题标题】:What's different between "def apply[T](c:T)" and "type T;def apply(c:T)"“def apply[T](c:T)”和“type T;def apply(c:T)”有什么不同
【发布时间】:2020-03-27 15:23:19
【问题描述】:

我有这个程序:

object B{
  def apply[T](c:T)={}
}

object C{
  type T
  def apply(c:T)={}
}

object A extends App{
  val d=B{println(1);2}
  val e=C{println(1);2}
}

一行

val e = C{println(1);2}

告诉我错误:类型不匹配,预期 C.T,实际:2

为什么我不能写

type T

def apply(c:T)

好像是一样的

apply[T](c:T)

我写的时候T是什么类型

val d=B{println(1);2}

我可以在这里写很多行!

因为T表示泛型,所以可以是Int,String,用户自定义类Apple,Orange...

什么是类型

println(1);2

是否有“代码行”类型?

谢谢!

【问题讨论】:

  • def apply[T](c: T) 中,T 的意思是“无论c 在每次调用中的类型”。而在第二个示例中, T 已经设置为 (在您的具体示例中,编译器可能推断出 AnyNothing 因为您没有指定).
  • 块的类型是块上最后一个表达式的类型。因此{ println(...); 2 } 的类型为 Int
  • @LuisMiguelMejíaSuárez 其实我不认为T 会被推断为AnyNothing,我想它会保持抽象。错误是“找到:Int(2);需要:C.T”而不是“找到:Int(2);需要:Nothing”或“找到:Int(2);需要:Anystackoverflow.com/questions/11274533/…@987654322 @

标签: scala generics types type-inference type-members


【解决方案1】:

块的类型是块上最后一个表达式的类型。所以

{ println(...); 2 } 

类型为Int

BC 之间的区别在于类型成员和类型参数(12)之间的类型推断不同。

object B{
  def apply[T](c:T)={}
}

object C{
  type T
  def apply(c:T)={}
}

class C1[T]{
  def apply(c:T)={}
}

val d: Unit = B{println(1);2}
// val e: Unit = C{println(1);2} // doesn't compile
val e1: Unit = (new C1){println(1);2}

  // scalacOptions ++= Seq("-Xprint:typer", "-Xprint-types")
// val d: Unit = A.this{A.type}.B.apply{[T](c: T)Unit}[Int]{(c: Int)Unit}({
//   scala.Predef.println{(x: Any)Unit}(1{Int(1)}){Unit};
//   2{Int(2)}
// }{2}){Unit};
// val e: Unit = A.this{A.type}.C.apply{(c: A.C.T)Unit}({
//   println{<null>}(1{Int(1)}){<null>};
//   2{Int(2)}
// }{<null>}){<error>};
// val e1: Unit = new A.C1[Int]{A.C1[Int]}{()A.C1[Int]}(){A.C1[Int]}.apply{(c: Int)Unit}({
//   scala.Predef.println{(x: Any)Unit}(1{Int(1)}){Unit};
//   2{Int(2)}
// }{2}){Unit};

C 中输入T 仍然是抽象的

Use of abstract type in a concrete class?

Concrete classes with abstract type members

Scala中有关于类型推断的论文:

普洛西尼扎克,休伯特;奥德斯基,马丁。解密本地类型推断 https://infoscience.epfl.ch/record/214757

如果你想让e编译你可以指定T

val e: Unit = C.asInstanceOf[C.type{type T = Int}]{println(1);2}

【讨论】:

  • 嗯,有趣。由于对象是最终的,我不相信它可以保持抽象(当时我在手机旁,所以没办法检查)。一些测试证实它以某种方式满足Nothing &lt;:&lt; C.T &lt;:&lt; Any,但不满足C.T =:= AnyC.T =:= Nothing
  • @LuisMiguelMejíaSuárez 是的,从 2.7 github.com/scala/bug/issues/1753#issuecomment-292364630 开始在具体类中允许抽象类型成员,从 2.11 github.com/scala/scala/pull/4024 开始在对象中允许抽象类型成员
  • @LuisMiguelMejíaSuárez 使用scalacOptions ++= Seq("-Xprint:typer", "-Xprint-types") 调查推断类型更可靠。
猜你喜欢
  • 2017-05-15
  • 2015-02-27
  • 2020-10-03
  • 2019-08-08
  • 1970-01-01
  • 2014-12-04
  • 1970-01-01
  • 2016-06-14
  • 1970-01-01
相关资源
最近更新 更多