scala: есть ли в конструкторе различие между apply и неявным параметром?

#scala

#scala

Вопрос:

У меня есть класс, подобный этому:

 class A(arg: Int)(implicit i: Boolean) {
  def apply(v: Double): this.type = {
    // do stuff
    this
  }
}
  

и я хочу создать его экземпляр, инициализировав его и вызвав apply в одной строке:

 implicit val i = false
val a = A(arg=1)(v=2.0) // doesn't work
val a2 = (A(arg=1))(v=2.0) // doesn't work
  

К сожалению, компилятор предполагает, что v = 2.0 предназначено для неявного параметра, а не для apply(). Я перепробовал несколько разных синтаксисов с помощью inserting {}’s и () ‘s, но ни один из них не сработал. Я понимаю, что v можно было бы переместить в конструктор, но в моем случае это не вариант, потому что A является подклассом, и я не хочу добавлять v в каждый конструктор подкласса. Есть ли способ добиться этого? Спасибо.

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

1. @pst пробовал это, по какой-то причине не работает

2. A(1)|>(_(2.0)) … ну, наверное, не лучше.

Ответ №1:

Как насчет «некрасиво, но, кажется, работает»…

 class A(arg: Int)(implicit i: Boolean) {
  def apply(v: Double): this.type = this
}
implicit val i = false
// removing the :A makes this fail to run on simplyscala
val a1 = (new A(arg=1) : A)(v=2.0)
// also works with explicit method name
val a2 = new A(arg=1).apply(v=2.0)
// and works without implicit being ... implicitized
val a = new A(arg=1)(i)(v=2.0)
  

Честно говоря, понятия не имею 🙂 Однако рассмотрите это, что может дать некоторое представление:

 val a = (new A(arg=1))(2.0)
  
ошибка: несоответствие типов; 
 найдено: Double(2.0)
 требуется: логическое значение 
 значение a = (new A(arg=1))(2.0)

Вау!

Удачного кодирования.

Ответ №2:

(Я предполагаю, что у вас есть метод конструктора в сопутствующем объекте, поскольку вы его не используете new A .)

Один из вариантов — записать его в двух строках:

 val atmp = A(1)
val a = atmp(2.0)
  

… но это, конечно, не то, что вам нужно. Другим не менее неудовлетворительным вариантом было бы

 val a = A(1)(implicitly)(2.0)
  

если вы можете с этим смириться. Возможно, наименее уродливый способ сделать это — вызвать apply явно:

 val a = A(1).apply(2.0)
  

Наконец, вы могли бы добавить новый метод конструктора к сопутствующему объекту, который позаботится обо всем:

 object A {
  def apply(arg: Int, v: Double)(implicit i: Boolean) = A(arg)(i)(v)
}

val a = A(1, 2.0)
  

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

1. Мне нравится вариант 2, потому что он немного более явный, чем apply , и поскольку любой подход является более явным…