Перегрузка метода только для параметра типа в scala - PullRequest
0 голосов
/ 16 апреля 2020

Можно ли как-то добиться такого поведения в scala (у funcs то же имя и параметры, но они отличаются только типом возвращаемого значения и параметром типа)?

def a(i:Int): Int //1
def a[T](i: Int): Double //2

a(1) //call 1
a[Any](1) //call 2

Мотивация UPD:

Я пишу директиву akka-http auth, которая проверяет сеанс и авторизацию запроса пользователя в зависимости от параметров разрешения.

  1. Когда он получает только разрешение, он предоставляет только что заверенный User:

def auth(perm: String): Directive1[User]

Когда он получает Tuple разрешения с UUID, он получает (каким-то образом) требуемый объект этим UUID, проверяет разрешение, примененное к требуемому объекту, и предоставляет этот объект, а также User:

def auth[Entity](tup: (String, UUID)): Directive1[(User, Entity)]

и , когда он получает тот же Tuple, но без параметра типа, он должен проверить разрешение, примененное к требуемому объекту, но предоставить только аутентифицированные User:

def auth(tup: (String, UUID)): Directive1[User]

Идея состоит в том, чтобы иметь одинаковое имя директивы для всех случаев, но кажется, что невозможно различить a[T](i: Int): Int и a(i: Int): Double на уровне языка (из-за стирания типа).

Может быть, есть какие-то хитрости, использующие implicits, которые помогают достичь этого?

Ответы [ 4 ]

0 голосов
/ 16 апреля 2020

Я думаю, что у вас есть проблема разделения здесь.

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

Это простой пример того, что может работать:

def route =
  auth { authUser =>
    (pathEnd | pathSingleSlash) {
      concat(
        get {
          val data = load(authUser, staticUuid)

          ???
        },
        post {
          decodeRequest {
            entity(as[MyRequestBody]) { myRequest =>
              val data = load(authUser, myRequest.uuid)

              ???
            }
          }
        },
      )
    }
  }

Если это неудобно для все время передавайте authUser методам, делайте его implicit методов извлечения данных. И вы также можете сделать операцию загрузки директивой, но директивой, отличной от auth.

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

0 голосов
/ 16 апреля 2020

Может быть, попытаться устранить неоднозначность с типом ascription вроде так

def a(i:Int): Int = 1
def a[T](i: Int): Double = 2

a(1): Int // res0: Int = 1
a[Any](1) // res1: Double = 2.0
0 голосов
/ 16 апреля 2020

Мой ответ немного обобщен c подход:

def add(a: Int): Int = a + 1
def add[T](a: T)(implicit num: Numeric[T]): Double = {
  num.toDouble(a) + 2.3
}

println(add(5)) // 6
println(add[Int](6)) // 8.3

Пример Scast ie

0 голосов
/ 16 апреля 2020

Из-за стирания типа эти 2 метода будут иметь одинаковую подпись.

@ class Test {
  def a(i:Int): Int = 1
  def a[T](i: Int): Double = 2.0
  }
defined class Test

@ new Test()
res24: Test = ammonite.$sess.cmd23$Test@7441edeb

@ new Test().a(1)
cmd25.sc:1: ambiguous reference to overloaded definition,
both method a in class Test of type [T](i: Int)Double
and  method a in class Test of type (i: Int)Int
match argument types (Int)
val res25 = new Test().a(1)
                       ^
Compilation Failed

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

@ class Test {
  def a(i:Int): Int = 1
  def a()(i: Int): Double = 2.0
  }
defined class Test

@ new Test().a(1)
res26: Int = 1

@ new Test().a()(1)
res27: Double = 2.0

Так ... в зависимости от того, сколько и что вы можете изменить, да или нет. В целом это плохая идея. Редко у вас есть веская причина перегрузить метод, и в этом случае перегрузка почти наверняка является анти-паттерном.

...