Что означает оператор `#` в Scala?

131

Я вижу этот код в этом блоге: Программирование на уровне типов в Scala :

// 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]
}

В #коде есть оператор, R#X[R#Next]которого я никогда не видел. Поскольку его трудно искать (игнорируется поисковыми системами), кто может сказать мне, что это означает?

Freewind
источник
1
«знак фунта» иногда называют «октатропом» (поиск в Google привел меня на эту страницу).
philwalk 01
3
Сделай этого окторпа или
окторпа
Что насчет других операторов, таких как # + и # - (см. Github.com/tpolecat/doobie/blob/series/0.4.x/yax/h2/src/main/… )? Есть исчерпывающий список?
Маркус Бартлен 05

Ответы:

240

Чтобы объяснить это, мы сначала должны объяснить вложенные классы в Scala. Рассмотрим этот простой пример:

class A {
  class B

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

Теперь попробуем что-нибудь с этим:

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)
                   ^

Когда вы объявляете класс внутри другого класса в Scala, вы говорите, что каждый экземпляр этого класса имеет такой подкласс. Другими словами, нет A.Bкласса, но есть a1.Bи a2.Bклассы, и они разные классы, так как сообщение об ошибке говорит нам выше.

Если вы этого не поняли, найдите типы, зависящие от пути.

Теперь #это дает вам возможность ссылаться на такие вложенные классы, не ограничивая их конкретным экземпляром. Другими словами, нет A.B, но есть A#B, что означает Bвложенный класс любого экземпляра A.

Мы можем увидеть это в работе, изменив код выше:

class A {
  class B

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

И попробуем:

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.
Дэниел С. Собрал
источник
Отличный пример. Я полностью согласен с тем, что это работает, но это трудно понять: scala> classOf [A # B] res7: Class [A # B] = class A $ B scala> classOf [aB] res8: Class [aB] = class A $ B. что означает, что на самом деле они одного типа?
Chiron
2
Их значения имеют одинаковое строковое представление - и они могут даже быть равными. Classпредставляет собой представление классов Java во время выполнения, и оно ограничено даже в Java. Например, List<String>и List<Integer>иметь такое же время выполнения Class. Если Classон недостаточно богат для представления типов Java , он почти бесполезен при представлении типов Scala . Опять же, res7: Class[A#B] = class A$Bслева от знака равенства является тип, справа от типа равенства, если значение, которое является представлением класса среды выполнения Java .
Дэниел С. Собрал
13

Он известен как проекция типа и используется для доступа к членам типа.

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

scala> val x = null.asInstanceOf[R#A]
x: Int = 0
missingfaktor
источник
6
Это не ответ. Он в основном показывает тот же код, что и вопрос, только немного сокращенный. В чем, например, разница в обозначениях точек? Где бы я использовал этот # в реальном коде?
notan3xit
2
@ notan3xit, возможно, это не ответ на то, что вы хотели спросить. Но вы спросили: «... чего я никогда не видел. Поскольку его трудно искать (игнорируется поисковыми системами), кто может сказать мне, что это означает?»
nafg