Co oznacza operator `# 'w Scali?

131

Widzę ten kod na tym blogu: Programowanie na poziomie typu w Scali :

// define the abstract types and bounds
trait Recurse {
  type Next <: Recurse
  // this is the recursive function definition
  type X[R <: Recurse] <: Int
}
// implementation
trait RecurseA extends Recurse {
  type Next = RecurseA
  // this is the implementation
  type X[R <: Recurse] = R#X[R#Next]
}
object Recurse {
  // infinite loop
  type C = RecurseA#X[RecurseA]
}

W #kodzie jest operator, R#X[R#Next]którego nigdy nie widziałem. Ponieważ wyszukiwanie jest trudne (ignorowane przez wyszukiwarki), kto może mi powiedzieć, co to oznacza?

Freewind
źródło
1
„znak funta” jest czasami nazywany „oktatropem” (ta wyszukiwarka Google doprowadziła mnie do tej strony).
philwalk
3
Zrób to octothorpe lub octothorp
smparkes
A co z innymi operatorami, takimi jak # + i # - (patrz github.com/tpolecat/doobie/blob/series/0.4.x/yax/h2/src/main/… )? Czy istnieje pełna lista?
Markus Barthlen

Odpowiedzi:

242

Aby to wyjaśnić, najpierw musimy wyjaśnić zagnieżdżone klasy w Scali. Rozważmy ten prosty przykład:

class A {
  class B

  def f(b: B) = println("Got my B!")
}

Teraz spróbujmy czegoś z tym:

scala> val a1 = new A
a1: A = A@2fa8ecf4

scala> val a2 = new A
a2: A = A@4bed4c8

scala> a2.f(new a1.B)
<console>:11: error: type mismatch;
 found   : a1.B
 required: a2.B
              a2.f(new a1.B)
                   ^

Kiedy deklarujesz klasę wewnątrz innej klasy w Scali, mówisz, że każda instancja tej klasy ma taką podklasę. Innymi słowy, nie ma A.Bklasy, ale istnieją a1.Bi a2.Bklasy i są to różne klasy, o czym informuje nas powyżej komunikat o błędzie.

Jeśli tego nie rozumiesz, poszukaj typów zależnych od ścieżki.

Teraz #umożliwia odwoływanie się do takich zagnieżdżonych klas bez ograniczania ich do konkretnej instancji. Innymi słowy, nie ma A.B, ale istnieje A#B, co oznacza Bzagnieżdżoną klasę dowolnej instancji A.

Możemy to zobaczyć w działaniu, zmieniając powyższy kod:

class A {
  class B

  def f(b: B) = println("Got my B!")
  def g(b: A#B) = println("Got a B.")
}

I wypróbować:

scala> val a1 = new A
a1: A = A@1497b7b1

scala> val a2 = new A
a2: A = A@2607c28c

scala> a2.f(new a1.B)
<console>:11: error: type mismatch;
 found   : a1.B
 required: a2.B
              a2.f(new a1.B)
                   ^

scala> a2.g(new a1.B)
Got a B.
Daniel C. Sobral
źródło
Doskonały przykład. Całkowicie zgadzam się, że to działa, ale trudno to zrozumieć: scala> classOf [A # B] res7: Class [A # B] = class A $ B scala> classOf [aB] res8: Class [aB] = class A $ B. co oznacza, że ​​faktycznie mają ten sam typ?
Chiron
2
Ich wartości mają tę samą reprezentację łańcuchową - a nawet mogą być równe. Classjest reprezentacją klas Java w czasie wykonywania i jest ograniczona nawet w Javie. Na przykład List<String>i List<Integer>mają to samo środowisko wykonawcze Class. Jeśli Classnie jest wystarczająco bogaty, aby reprezentować typy Java , jest prawie bezużyteczny podczas reprezentowania typów Scala . Ponownie, po res7: Class[A#B] = class A$Blewej stronie znaku równości znajduje się typ, a na prawo od typu równości, jeśli wartość jest reprezentacją klasy w środowisku wykonawczym Java .
Daniel C. Sobral,
13

Jest znany jako projekcja typu i służy do uzyskiwania dostępu do elementów członkowskich typu.

scala> trait R {
     |   type A = Int
     | }
defined trait R

scala> val x = null.asInstanceOf[R#A]
x: Int = 0
missingfaktor
źródło
6
To jest brak odpowiedzi. Zasadniczo pokazuje ten sam kod co pytanie, tylko lekko skrócony. Jaka jest na przykład różnica w notacji punktowej? Gdzie użyłbym tego # w prawdziwym kodzie?
notan3xit
2
@ notan3xit może to nie jest odpowiedź na to, o co chciałeś zapytać. Ale zapytałeś: „… czego nigdy nie widziałem. Ponieważ wyszukiwanie jest trudne (ignorowane przez wyszukiwarki), kto może mi powiedzieć, co to znaczy?”
nafg