Я использую заводской шаблон с дженериками. Идея состоит в том, чтобы создать правильную реализацию (BlockType1Impl или BlockType2Impl) в зависимости от типа A, который является классом case (BlockchainType1 или BlockchainType2). Я не устанавливаю никаких ограничений типа.

Код

После просмотра этого примера на {{X0 }} метод с универсальными типами

trait BlockTypeFactory[A]{

  def findTransactions( blocks: Seq[A], address: String): Seq[TransactionResponse]

}


object BlockTypeFactory{
  // I want this method to return the correct implementations 
  def getBlockExplorer[A](blockType: A): BlockTypeFactory[A] = {
    blockType match {
      case type1: BlockchainType1 => new BlockTypeFactory[BlockchainType1](new BlockType1Impl)
    // error : Expression of type BlockTypeFactory[BlockType1Impl] doesn't conform with the expected type BlockTypeFactory[A]
      case type2: BlockchainType2 => new BlockType2Impl
    }
  }

def apply[A](implicit ev: BlockTypeFactory[A],blockType: A):BlockTypeFactory[A] = ev

}

Но я получаю ошибку об ожидаемом типе . Что именно не так?

Другие классы

class BlockType1Impl extends BlockTypeFactory[BlockchainType1]

class BlockType2Impl extends BlockTypeFactory[BlockchainType2]

case class BlockchainType1(...)
case class BlockchainType2(...)
3
Raymond Chenon 23 Сен 2018 в 01:12

1 ответ

Лучший ответ

Ваш код не работает, потому что компилятор не знает, где взять неявные экземпляры BlockTypeFactory.

Для достижения своей цели вы можете использовать классы типов.

Этот способ является расширяемым, вы можете иметь более одной фабрики для каждого класса, если хотите (вам нужно поиграть с неявной областью действия), и вы можете определить стандартные фабрики для некоторых типов.

Вы можете закодировать неявные экземпляры ваших классов case внутри объекта BlockTypeFactory, но обычно это делается именно так.

// your type class
trait BlockTypeFactory[A] {
  def create:A
} 

case class BlockchainType1()

object BlockchainType1 {
  // type 1 impl
  implicit val factory:BlockTypeFactory[BlockchainType1] = new BlockTypeFactory[BlockchainType1] {
    def create: BlockchainType1 = BlockchainType1()
  }
}

case class BlockchainType2()

object BlockchainType2 {
  // type 2 impl
  implicit val factory:BlockTypeFactory[BlockchainType2] = new BlockTypeFactory[BlockchainType2] {
    def create: BlockchainType2 = BlockchainType2()
  }
}

object BlockTypeFactory {

  // get factory
  def apply[A:BlockTypeFactory]:BlockTypeFactory[A] = implicitly[BlockTypeFactory[A]]

  // or create
  def create[A:BlockTypeFactory]:A = implicitly[BlockTypeFactory[A]].create

}

val instance1 = BlockTypeFactory[BlockchainType1].create

val instance2 = BlockTypeFactory.create[BlockchainType2]

Этот шаблон называется классом типа и используется для получения специального полиморфизма. В вашем примере вам понадобится полиморфный метод findTransactions для каждого класса, определенного в BlockTypeFactory.

3
Sebastian Celestino 23 Сен 2018 в 05:46