#scala
#scala
Вопрос:
Я пытаюсь объявить функцию в черте, которая принимает переменное количество аргументов, и во время реализации черты я бы расширил количество аргументов. Как это можно сделать в Scala
Я ожидаю получить код, подобный приведенному ниже.
trait Column {
def rule
}
case object FirstColumn extends Column{
def rule(s: String) : String
}
case object SecondColumn extends Column{
def rule(s1: String, s2: String) : String
}
Я пробовал использовать строки * , но это не позволяет мне увеличить количество аргументов во время реализации. Я понимаю, что существуют различные способы решения этой проблемы, но я специально ищу указанную выше подпись для моей команды для написания функций.
Комментарии:
1. Что за «вышеуказанная подпись» ? У вас есть три метода с тремя разными сигнатурами.
2. Если вы объявляете
rule
, что принимаете переменные аргументы в чертеже, то вы обещаете, что реализация работает для любого числа аргументов, а не только для некоторого определенного количества аргументов, зависящего от реализации. Таким образом,FirstColumn
который предоставляет одноразовую версию функции, неправильно реализует признак.3. Другими словами, если у меня есть
Column
, как бы я вызвалrule
ее? Если я передаю один аргумент, и он оказываетсяSecondColumn
, это ошибка. И наоборот, если я передаю два, и этоFirstColumn
. Итак, если у вас естьColumn
, то вы не можете сделать с ней ничего типобезопасного, что сводит на нет смысл того, что это вообще черта.4. Спасибо Сильвио.. Я думаю, что type safe решит мою проблему.. Я больше думал о том, чтобы иметь что-то вроде «любой класс, который реализует этот признак, всегда должен иметь функцию с именем «rule» и позволять пользователю указывать аргументы, которые они желают», но это противоречит цели trait, и я никогда не смогу вызвать его с помощью «Column».. Спасибо за комментарий
5. Спасибо Луису.. Это было понятно..
Ответ №1:
Это в первую очередь расширяет мой комментарий к вопросу. Этот ответ приближает вас настолько, насколько Scala позволяет вам приблизиться к тому, что вы хотите, но он также показывает, почему, вероятно, не очень хорошая идея делать то, что вы делаете.
Вы можете выразить (что-то близкое к) желаемый тип, но я не уверен, что вы намерены получить. Во-первых, если вы хотите использовать разные типы списков аргументов, то Column
он должен быть универсальным.
trait Column[-A] {
def rule(arg: A): String
}
Затем мы можем реализовать ваши объекты case как подклассы соответствующей параметризации этого.
case object FirstColumn extends Column[String] {
def rule(arg: String): String =
"stub implementation"
}
case object SecondColumn extends Column[(String, String)] {
def rule(arg: (String, String)): String =
"stub implementation"
}
Обратите внимание, что FirstColumn
и SecondColumn
не наследуются от одного и того же Column[A]
, поскольку они не реализуют один и тот же метод. Мы можем заставить их иметь общий тип, но… не очень полезным способом.
Один из вариантов — найти общий супертип Column[String]
and Column[(String, String)]
, который (поскольку аргумент контравариантен) сродни поиску общего подтипа String
and (String, String)
. Ближайший распространенный подтип — это … Null
. Это бесполезно, если вы только не планируете передавать null
в свой rule
.
Вместо этого мы можем использовать existentials.
val foo: Column[_] = FirstColumn
val bar: Column[_] = SecondColumn
Теперь мы потеряли всю информацию о типе. Вы можете получить доступ к слоту foo.rule
и распечатать его, но вы не можете вызвать его, потому что мы не знаем, что нам нужно передать. Вам нужно будет выполнить приведение, чтобы вернуть ее к удобному формату.
Смысл, который я здесь подчеркиваю, заключается в том, что да, это выполнимо, но как только вы потеряете столько информации о типе, сколько отдаете, в этом не будет особого смысла. Система типов правильно сообщает нам, что foo
и bar
практически не имеют ничего общего, кроме существования метода с именем rule
, который принимает … какой-то аргумент. С точки зрения теории типов, трудно придумать что-то более неинтересное, чем это.
Комментарии:
1. Спасибо Сильвио.. Это помогает.. Моим вариантом использования было перебрать все объекты case и получить метод run и передать его как функцию высокого порядка в Spark UDF. Мое намерение состоит в том, чтобы создать универсальную функцию, которая может принимать n количество аргументов и возвращать строку.. Я передам эту функцию как функцию HO. Пожалуйста, дайте мне знать, если у вас есть какие-либо мысли по этому поводу, и ваш ответ был очень полезен для меня.. Спасибо..
2. @NareshKumarSundaramKrishnam Итак, по сути, у вас есть DF с неизвестным количеством строк-столбцов, и вы хотите выполнить над ним какую-то операцию, ориентированную на строки?