任意の種類のタイプと抽象非型部材定義の{}
囲まれたシーケンスが続くことができます。これは「洗練」として知られており、洗練されている基本タイプに対して追加の精度を提供するために使用されます。実際には洗練された型の抽象型メンバに制約を表現するために洗練が最も一般的に使用されます。
このシーケンスは空であることが許されており、シェイプレスソースコードで見ることができる形式で、T {}
はタイプがT
で、空のリファインメントです。空のリファインメントは空です...したがって、追加の制約は洗練されたタイプに追加されないため、タイプT
とT {}
は同等です。
scala> implicitly[Int =:= Int {}]
res0: =:=[Int,Int] = <function1>
なぜ私はシェイプレスでこのような明らかに無意味なことをするのでしょうか?それは洗練の存在と型推論の間の相互作用のためです。 Scala言語仕様のthe relevant sectionを見ると、タイプ推論アルゴリズムは少なくともいくつかの状況でシングルトンタイプを推測しないようにしようとします。あなたがf2
の定義から見ることができるようにここで
scala> class Foo ; val foo = new Foo
defined class Foo
foo: Foo = [email protected]
scala> val f1 = foo
f1: Foo = [email protected]
scala> val f2: foo.type = foo
f2: foo.type = [email protected]
、ちょうどそれを行うことの一例であるScalaのコンパイラは、値foo
は、より正確なタイプfoo.type
(すなわち。val foo
のシングルトン型)を持っていることを知っていますただし、明示的に要求されない限り、より正確な型を推測することはありません。代わりに、f1
の場合のように非シングルトン(すなわち、拡大)タイプFoo
を推論します。
しかし、型崩れでWitness
の場合、私は明示的に(Witness
の全体のポイントは、シングルトンタイプ経由型と値のレベルの間を通過するために私たちを有効にある)シングルトン型はvalue
メンバーの用途のために推論することがをしたいです、そうするためにScalaコンパイラに説得できる方法はありますか?
それはあなたがs2
が割り当てられているのに対し、最初のケースs1
に広がっタイプString
として型付けされた、上記のREPL転写産物で見ることができるように空の微細化はまさにその、
scala> def narrow[T <: AnyRef](t: T): t.type = t
narrow: [T <: AnyRef](t: T)t.type
scala> val s1 = narrow("foo") // Widened
s1: String = foo
scala> def narrow[T <: AnyRef](t: T): t.type {} = t // Note empty refinement
narrow: [T <: AnyRef](t: T)t.type
scala> val s2 = narrow("foo") // Not widened
s2: String("foo") = foo
ないことが判明シングルトンタイプString("foo")
。
これはSLSによって義務付けられていますか?いいえ、でもそれはそれと一致していて、何らかの意味があります。 Scalaの型推論機構の多くは、spec'edではなく実装定義されており、これはおそらくそれの最も驚くべき問題の1つです。
何を「広げる」んコミットメッセージに意味: 'どうやら空の微細化は意味「me'.'を広げませんか? –
拡張は暗黙的な型の拡大を指しています(例えば、List1(2.0)はList [Double]なので、int1は2.0に一致するように2倍に拡大できるためです)。この主旨は説明するのに役立つかもしれません:https://gist.github.com/milessabin/65fa0d4ef373781d3ab4 –
Widenは、シングルトンタイプを推測するのを避けたいので、シングルトンタイプの 'X.type'から' object X'のタイプを広げることを意味します。ここではシングルトンタイプが望ましい。 –