API duckduckgo не возвращает результаты

Начнем с циклической зависимости.

trait A {
  selfA: B =>
  def fa: Int }

trait B {
  selfB: A =>
  def fb: String }

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

trait A1 extends A {
  selfA1: B =>
  override def fb = "B's String" }
trait B1 extends B {
  selfB1: A =>
  override def fa = "A's String" }
val myObj = new A1 with B1

Хотя, если вы переопределите член типа self, вы потеряете доступ к исходному элементу, к которому все еще можно получить доступ через супер, используя наследование. Итак, что действительно наработано с использованием наследования:

trait AB {
  def fa: String
  def fb: String }
trait A1 extends AB
{ override def fa = "A's String" }        
trait B1 extends AB
{ override def fb = "B's String" }    
val myObj = new A1 with B1

Теперь я не могу утверждать, что понимаю все тонкости шаблона пирога, но мне кажется, что основным методом обеспечения модульности является составление а не наследования или типов.

Версия наследования короче, но основная причина, по которой я предпочитаю наследование по типам self, заключается в том, что мне гораздо сложнее получить правильный порядок инициализации с собственными типами. Однако есть некоторые вещи, которые вы можете делать с самими типами, которые вы не можете сделать с наследованием. Типы типов могут использовать тип, тогда как для наследования требуется черта или класс:

trait Outer
{ type T1 }     
trait S1
{ selfS1: Outer#T1 => } //Not possible with inheritance.

Вы даже можете сделать:

trait TypeBuster
{ this: Int with String => }

Хотя вы никогда не сможете создать экземпляр. Я не вижу абсолютной причины для того, чтобы не унаследовать от типа, но я уверен, что было бы полезно иметь классы и черты конструктора путей, поскольку у нас есть типы / классы конструктора типов. Как, к сожалению,

trait InnerA extends Outer#Inner //Doesn't compile

Мы имеем это:

trait Outer
{ trait Inner }
trait OuterA extends Outer
{ trait InnerA extends Inner }
trait OuterB extends Outer
{ trait InnerB extends Inner }
trait OuterFinal extends OuterA with OuterB
{ val myV = new InnerA with InnerB }

Или это:

  trait Outer
  { trait Inner }     
  trait InnerA
  {this: Outer#Inner =>}
  trait InnerB
  {this: Outer#Inner =>}
  trait OuterFinal extends Outer
  { val myVal = new InnerA with InnerB with Inner }

. Одна точка, которая должна быть больше сочувствующей, заключается в том, что черты могут расширяет классы. Спасибо Дэвиду Маклверу за это. Вот пример из моего собственного кода:

class ScnBase extends Frame
abstract class ScnVista[GT <: GeomBase[_ <: TypesD]](geomRI: GT) extends ScnBase with DescripHolder[GT] )
{ val geomR = geomRI }    
trait EditScn[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
trait ScnVistaCyl[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]

ScnBase наследуется от класса кадра Swing , поэтому его можно использовать как тип self, а затем смешать в end (при создании экземпляра). Однако val geomR необходимо инициализировать, прежде чем использовать его, наследуя черты. Поэтому нам нужен класс для принудительной инициализации geomR. Класс ScnVista может затем наследоваться из-за множества ортогональных признаков, которые сами могут быть унаследованы. Использование нескольких параметров типа (generics) предлагает альтернативную форму модульности.

13
задан Community 23 May 2017 в 22:32
поделиться