Является ли зависимый от пути тип подтипом? - PullRequest
3 голосов
/ 12 мая 2011
trait A {
  trait B {
    def foo: A.this.B = new B{}
    def bar: A#B      = foo 
    def baz: A.this.B = bar // type mismatch; found : A#B required: A.this.B 
  }
}

Прав ли я, что A.this.B является зависимым от пути типом ?!(Это мое понимание до сих пор) Означает ли приведенный выше пример, что тип A.this.B является подтипом A#B?(Если да, я думаю, разница в том, что экземпляр A.this.B имеет ссылку на экземпляр A по сравнению с A#B, который не имеет?) Кто-нибудь знает поучительное объяснение, которое разрешает мою путаницу с этими двумятипы?

Ответы [ 3 ]

14 голосов
/ 12 мая 2011

Отличная книга Программирование в Scala имеет довольно хорошее объяснение :

class Outer {
  class Inner
}

В Scala внутренний класс адресуется с помощью выражения Outer#Inner вместо Outer.Inner в Java,Синтаксис . зарезервирован для объектов.Например, представьте, что вы создаете два объекта типа Outer, например:

val o1 = new Outer
val o2 = new Outer

Здесь o1.Inner и o2.Inner - это два зависимых от пути типа (и это разные типы).Оба эти типа соответствуют (являются подтипами) более общего типа Outer#Inner, который представляет класс Inner с произвольным внешним объектом типа Outer.Напротив, тип o1.Inner относится к классу Inner с определенным внешним объектом (тот, на который ссылается o1).Аналогично, тип o2.Inner относится к классу Inner с другим конкретным внешним объектом (объект, на который ссылается o2).

В Scala, как и в Java, экземпляры внутреннего класса содержат ссылку на вмещающий объект.экземпляр внешнего класса.Это позволяет внутреннему классу, например, получать доступ к членам своего внешнего класса.Таким образом, вы не можете создать экземпляр внутреннего класса, не указав каким-либо образом экземпляр внешнего класса.Один из способов сделать это - создать экземпляр внутреннего класса внутри тела внешнего класса.В этом случае будет использован текущий экземпляр внешнего класса (на который есть ссылка).Другой способ - использовать тип, зависящий от пути.Например, поскольку тип o1.Inner называет конкретный внешний объект, вы можете создать его экземпляр:

scala> new o1.Inner
res1: o1.Inner = Outer$Inner@13727f

Результирующий внутренний объект будет содержать ссылку на свой внешний объект, объект, на который ссылается o1.В отличие от этого, поскольку тип Outer#Inner не называет ни одного конкретного экземпляра Outer, вы не можете создать его экземпляр:

scala> new Outer#Inner
<console>:6: error: Outer is not a legal prefix for
  a constructor
       new Outer#Inner
                 ^
5 голосов
/ 12 мая 2011

Короче говоря: Да, это

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

2 голосов
/ 12 мая 2011

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

...