/ / scala - ogranicz typ ogólny do określonych typów - scala

scala - ogranicza typ rodzajowy do konkretnych typów - scala

od czasu do czasu mam do czynienia z javą, która ma w sobie takie rzeczy:

def printDbl(d:Double) { println("dbl: " + d) }
def printInt(i:Int) { println("int: " + i) }

naturalnie chciałbym owinąć to w jakąś scalę, która kończy się tak:

def print[T:Manifest] (t:T) {
if (manifest[T] <:< manifest[Int]) { printInt(t.asInstanceOf[Int]) ; return }
if (manifest[T] <:< manifest[Double]) { printDbl(t.asInstanceOf[Double]) ; return }

throw new UnsupportedOperationException("not implemented: " + manifest[T])
}

ale kiedy uruchamiam następujące, otrzymuję wyjątek czasu wykonywania:

print(1)
print(2.0)
print("hello")

Wydaje mi się, że istnieje sposób na złapanie tego w czasie kompilacji, ale nie mogę tego wygooglować. Może jakieś sprytne niejawne konwersje?

Odpowiedzi:

6 dla odpowiedzi № 1

Dlaczego po prostu nie skorzystasz z przeciążania metod i nie napiszesz swojego wrappera Scali w ten sposób?:

object Printer {
def print(d: Double) { printDbl(d) }
def print(i: Int) { printInt(i) }
}

Jest to bardzo proste i zapewnia pożądane zachowanie:

import Printer._
print(1.)          // dbl: 1.0
print(1)           // int: 1
print("hello")     // compile-time type error

1 dla odpowiedzi nr 2
scala> object SpecType {
|   trait SpecType[T] {
|     def is(s: String): Boolean
|   }
|   implicit object DoubleType extends SpecType[Double] {
|     def is(s: String) = s == "Double"
|   }
|   implicit object IntType extends SpecType[Int] {
|     def is(s: String) = s == "Int"
|   }
| }
defined module SpecType


scala> import SpecType._
import SpecType._

scala> def print[T: SpecType](x: T) {
|   if(implicitly[SpecType[T]].is("Int")) println("Int")
|   if(implicitly[SpecType[T]].is("Double")) println("Double")
| }
print: [T](x: T)(implicit evidence$1: SpecType.SpecType[T])Unit

scala> print(1)
Int

scala> print(1.0)
Double

scala> print("")
<console>:21: error: could not find implicit value for evidence parameter of typ
e SpecType.SpecType[String]
print("")

0 dla odpowiedzi № 3

to jest najlepsze, jakie wymyśliłem

class CanPrint[T] (t:T) { def getT = t}
implicit def canPrint(i:Int) = new CanPrint[Int](i)
implicit def canPrint(d:Double) = new CanPrint[Double](d)

def print[T:Manifest] (t:CanPrint[T]) {
if (manifest[T] <:< manifest[Int]) { printInt(t.getT.asInstanceOf[Int]) ; return }
if (manifest[T] <:< manifest[Double]) { printDbl(t.getT.asInstanceOf[Double]) ; return }

throw new UnsupportedOperationException("not implemented: " + manifest[T])
}

poniższe nie kompiluje się

print(1)
print(1.0)
print("hello")

a następujące robi to, czego oczekuję

print(1)
print(1.0)

jednak jest to zły kod, ponieważ muszęzaimportuj niejawne def, aby zadziałało, a jako konsument tego kodu widzę tylko podpis metody mówiący, że muszę przekazać obiekt CanPrint, który mogę utworzyć.

print(new CanPrint("hello")) // pwned

czy mogę uczynić konstruktora prywatnym i dostępnym tylko dla niejawnych metod lub niektórych takich?


0 dla odpowiedzi nr 4
def printDbl(d:Double) { println("dbl: " + d) }
def printInt(i:Int) { println("int: " + i) }

trait Printer[T] { def print(t:T) }
class PD extends Printer[Double] { def print(d:Double) = printDbl(d) }
class PI extends Printer[Int] { def print(i:Int) = printInt(i) }
implicit val pd = new PD()
implicit val pi = new PI()

def print[T](t:T)(implicit printer:Printer[T]) = printer.print(t)

print(1) // 1
print(2.0) // 2.0
print("hello") // Error:(88, 7) could not find implicit value for parameter printer: A$A336.this.Printer[String]