Oto kilka powodów, dla których warto skorzystać z cudownie prostej metody implicitly
.
Aby zrozumieć / rozwiązać problemy z widokami niejawnymi
Widok niejawny może zostać wyzwolony, gdy prefiks wyboru (rozważmy na przykład, the.prefix.selection(args)
że nie zawiera elementu członkowskiego, selection
który ma zastosowanie do args
(nawet po próbie konwersji za args
pomocą widoków niejawnych). W tym przypadku kompilator szuka niejawnych elementów członkowskich, zdefiniowanych lokalnie w bieżących lub obejmujących zakresach, dziedziczonych lub zaimportowanych, które są funkcjami z tego typu the.prefix
do typu ze selection
zdefiniowanymi lub równoważnymi metodami niejawnymi.
scala> 1.min(2) // Int doesn't have min defined, where did that come from?
res21: Int = 1
scala> implicitly[Int => { def min(i: Int): Any }]
res22: (Int) => AnyRef{def min(i: Int): Any} = <function1>
scala> res22(1) //
res23: AnyRef{def min(i: Int): Int} = 1
scala> .getClass
res24: java.lang.Class[_] = class scala.runtime.RichInt
Niejawne widoki można również wyzwalać, gdy wyrażenie nie jest zgodne z oczekiwanym typem, jak poniżej:
scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1
Tutaj kompilator szuka tej funkcji:
scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>
Dostęp do niejawnego parametru wprowadzonego przez powiązanie z kontekstem
Niejawne parametry są prawdopodobnie ważniejszą cechą Scali niż niejawne widoki. Obsługują wzorzec klasy typu. Biblioteka standardowa używa tego w kilku miejscach - zobacz scala.Ordering
i jak jest używany w SeqLike#sorted
. Niejawne parametry są również używane do przekazywania manifestów tablicowych i CanBuildFrom
wystąpień.
Scala 2.8 pozwala na skróconą składnię niejawnych parametrów, zwanych granicami kontekstu. Krótko mówiąc, metoda z parametrem typu, A
która wymaga niejawnego parametru typu M[A]
:
def foo[A](implicit ma: M[A])
można przepisać jako:
def foo[A: M]
Ale jaki jest sens przekazywania niejawnego parametru bez nadawania mu nazwy? Jak może to być przydatne podczas wdrażania metody foo
?
Często nie trzeba odwoływać się bezpośrednio do niejawnego parametru, będzie on tunelowany jako niejawny argument do innej wywoływanej metody. Jeśli jest to potrzebne, nadal możesz zachować zwięzłą sygnaturę metody za pomocą Context Bound i wywołać, implicitly
aby zmaterializować wartość:
def foo[A: M] = {
val ma = implicitly[M[A]]
}
Jawne przekazanie podzbioru niejawnych parametrów
Załóżmy, że wywołujesz metodę, która ładnie wypisuje osobę, używając podejścia opartego na klasie typów:
trait Show[T] { def show(t: T): String }
object Show {
implicit def IntShow: Show[Int] = new Show[Int] { def show(i: Int) = i.toString }
implicit def StringShow: Show[String] = new Show[String] { def show(s: String) = s }
def ShoutyStringShow: Show[String] = new Show[String] { def show(s: String) = s.toUpperCase }
}
case class Person(name: String, age: Int)
object Person {
implicit def PersonShow(implicit si: Show[Int], ss: Show[String]): Show[Person] = new Show[Person] {
def show(p: Person) = "Person(name=" + ss.show(p.name) + ", age=" + si.show(p.age) + ")"
}
}
val p = Person("bob", 25)
implicitly[Show[Person]].show(p)
A jeśli chcemy zmienić sposób wyświetlania nazwy? Możemy jawnie wywołać PersonShow
, jawnie przekazać alternatywę Show[String]
, ale chcemy, aby kompilator przekazał Show[Int]
.
Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)
Implicitly
jest dostępny w Scali 2.8 i jest zdefiniowany w Predef jako:Jest powszechnie używany do sprawdzania, czy niejawna wartość typu
T
jest dostępna i zwraca ją, jeśli tak jest.Prosty przykład z prezentacji retronimu :
źródło
implicitly[Ordering[(Int, String)]].compare( (1, "b"), (1, "a") )
, szczególnie w celu pobrania niejawnego parametru wprowadzonego przez Context Bound:def foo[A: Ordering](a1: A, a2: A) = implicitly[Ordering[A]].compare(a1, a2)
Odpowiedzią typu „nauczysz łowić ryby” jest skorzystanie z alfabetycznego indeksu elementów dostępnych obecnie w nocnikach Scaladoc . Litery (i
#
, w przypadku nazw innych niż alfabetyczne) u góry panelu pakietu / klasy są łączami do indeksu nazw członków zaczynających się od tej litery (we wszystkich klasach). Jeśli wybierzeszI
np. Znajdzieszimplicitly
wpis z jednym wystąpieniem wPredef
, który możesz odwiedzić z odnośnika tam.źródło
implicit
wydaje się być ważną cechą językową w Scali i zdecydowanie wartą właściwego wyjaśnienia. Myślenie, że dokumentacja wyszczególnia tylko liczbę podpisów typu, wydaje się bardziej intelektualną samozadowoleniem niż prawdziwą odpowiedzią. Zobacz szczegółowe pytania zadawane przez PO - co to jest i jak jest używane? Ani przez to nie odpowiedział, ani w nocnych dokumentach, do których nawet nie podajesz rzeczywistego linku. scala-lang.org/files/archive/nightly/docs/library/… To niczego nie uczy. Przykłady oryginalnych dokumentów można znaleźć w Niklaus Wirth lub Turbo Pascal. -1implicit
iimplicitly
są powiązane, ale całkiem różne. Słowoimplicit
kluczowe jest częścią języka.implicitly
jest zdefiniowany w zwykłym kodzie Scala w bibliotece standardowej. Ponieważ dokumenty on-line zawierają linki do źródeł, uważam, że nadal najlepiej jest kierować osoby pytające do tych dokumentów i do połączonego źródła.