Объединение нескольких значений, в которых тип имеет экземпляр Show

#scala #functional-programming #scala-cats

Вопрос:

Я хочу написать функцию showAll , которая принимает a List значений и выдает a String , полученное путем объединения String представлений каждого из значений, используя Show экземпляры, доступные в неявной области.

Не должно быть никаких ограничений на тип элементов списка, кроме наличия Show экземпляра.

Например:

 case class Person(name: String)
implicit val showPerson: Show[Person] = Show.by(_.name)
showAll(List(1, Person("Martin")))
 

следует выводить:

 1 Martin
 

В этом случае функция использует Show[Int] Show[Person] экземпляры и.

Какова была бы правильная подпись для функции?

Спасибо.

Комментарии:

1. Проблема в том, что список относится к типу List[Any] , для которого нет Show простого способа получить Show каждый элемент. Существует множество трюков, чтобы получить то, что вы хотите, от шаблона магнита до создания пользовательского класса, который заархивирует каждый элемент с его экземпляром show, до использования Shapeless для автоматического заархивирования.

2. Действительно, в этом-то и проблема. Моей первой мыслью было добавить какой-нибудь общий супертип T, а затем написать экземпляр show для T, но мне было интересно, смогу ли я решить эту проблему, просто каким-то образом улучшив подпись. Бесформенное выглядит интересно.

3. Проверьте это (найдите раздел «Бонусный раунд: как мы работаем с коллекциями?») — Если вам удастся заставить его работать, пожалуйста, напишите ответ! 🙂

4. Вы настаиваете на List этом, или варарги тоже будут работать на вас? Нравится showAll(1, person) ?

Ответ №1:

Вот мой пример кода , который, вероятно, решит вашу проблему. Я создал универсальный метод показать все, как вам нужно, чтобы отобразить элементы списка. также неявный метод для определенных значений полей. След микласса — это идентификатор. если Myclass не будет расширен ни на один случай, конкретное поле класса не будет напечатано.

 trait Myclass
  case class Person(name: String) extends Myclass
  case class Admin(name: String,age:Long) extends Myclass

  def main(args: Array[String]): Unit = {
    showAll[Myclass](List(1, 2, Person("Martin"),Admin("Bob",30)))
  }

  implicit def showField: String = "name"

  def showAll[T <: Myclass : ClassTag](listOfValues: List[Any]): Unit = {
    listOfValues.foreach { data =>
      if (data.isInstanceOf[T]) {
        val myInstance= data.asInstanceOf[T]
        val fld = myInstance.getClass.getDeclaredField(showField)
        fld.setAccessible(true)
        val value = fld.get(myInstance).asInstanceOf[String]
        print(value   " ")
      }
      else
        print(data   " ")
    }
  }