Строковый объект-компаньон в scala

Учитывая тип, который имеет «преобразователь», я хотел бы иметь автоматическое преобразование при вызове метода с использованием объекта-компаньона этого типа. То есть, учитывая следующее определение,

case class Converted(name: String)

trait Converter[A] {
  def perform: Converted
}

implicit val StringConverter = new Converter[String] {
  def perform = Converted("String")
}

заставить работать следующий код:

implicit def toConverter(a: String.type): Converted = 
  implicitly[Converter[String]].perform // Error: `Found String.type, required AnyRef`

def f(needsConverted: Converted) = ???

f(String) // <- That's what I would like to be able to write.

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

  1. Могу ли я компилировать f(String) с помощью имплицитов?

Если это невозможно для строк, как насчет классов, у которых есть объект-компаньон, могу ли я сделать это в общем случае, например:

object TheClass

case class TheClass()

implicit val TheClassConverter = new Converter[TheClass] {
  def perform = Converted("TheClass")
}

implicit def toConverter[A: Converter](a: A.type): Converted =
  implicitly[Converter[A]].perform // Error: `Not found value A`

implicit def toConverter(a: TheClass.type): Converted = 
  implicitly[Converter[TheClass]].perform // This works but is not generic

f(TheClass) // This works.
  1. Могу ли я сделать первый toConverter для компиляции?

person Mikaël Mayer    schedule 29.03.2017    source источник
comment
Я полагаю, есть веская причина, но почему бы вам не сделать implicit val TheClassConverter: Converter[TheClass.type] = ??? ?   -  person Jasper-M    schedule 29.03.2017
comment
Спасибо, что отвечаете на мой второй вопрос. Теперь я могу написать что-нибудь для String?   -  person Mikaël Mayer    schedule 29.03.2017
comment
хорошо, я нашел для String. Мне просто нужно определить object String... Если вы предоставите свой комментарий в качестве ответа, я могу его принять.   -  person Mikaël Mayer    schedule 29.03.2017
comment
Если ваш Converter[A] действительно не использует A нигде в своем теле, почему у него есть параметр типа? Если это так, наличие Converter[MyClass.type], когда вам нужно Converter[MyClass], не поможет.   -  person Alexey Romanov    schedule 30.03.2017
comment
Обратите внимание, что в приведенном выше вопросе был упрощенный пример для воспроизведения проблемы с имплицитами, но не беспокойтесь, в моем случае я использую параметр типа A в теле.   -  person Mikaël Mayer    schedule 30.03.2017


Ответы (3)


Вместо определения неявного экземпляра для типа MyClass вы можете определить неявный экземпляр для сопутствующего типа MyClass.type.

implicit val TheClassConverter: Converter[MyClass.type] = new Converted[MyClass.type] {
  def perform = Converted("MyClass")
}
person Jasper-M    schedule 29.03.2017

Могу ли я компилировать f(String) с использованием имплицитов?

Нет. Конечно, вы можете определить значение с именем String, но оно не будет связано с типом String.

implicit toConverter[A: Converter](a: A.type): Converted =
    implicitly[Converter[A]].perform

A в A.type должно быть значением; это не связано с параметром типа A.

На самом деле, что касается системы типов Scala, между классом/чертой и сопутствующим ему объектом нет никакой связи. Таким образом, вы не можете делать то, что хотите, в общем.

Конечно, если вы не настаиваете на использовании () вместо [], это становится тривиальным:

def f1[A: Converter] = f(implicitly[Converter[A]].perform)

f1[String]
f1[TheClass]
person Alexey Romanov    schedule 29.03.2017

Не уверен, чего вы пытаетесь достичь, но следующие работы для меня

case class Converted(name: String)

trait Converter[A] {
  def perform: Converted
}

implicit def toConverted(name: String) = Converted("String")
implicit def toIntConverted(int: Int) = Converted("Int")

def f(needsConverted: Converted): String = needsConverted.name

f("some")
f(5)
person mavarazy    schedule 29.03.2017
comment
Нет, я действительно хочу передать type в качестве входных данных для f, а не значения type. На данный момент я могу написать что-то вроде f(TheClass) последний пример моего второго вопроса, и только если у меня есть неявное от TheClass.type до Converter. Я хотел бы сделать то же самое для String, а также вообще, если у меня есть тип, который можно преобразовать в Converter - person Mikaël Mayer; 29.03.2017