代码之家  ›  专栏  ›  技术社区  ›  oluies

什么是Scala标识符“隐式”?

  •  154
  • oluies  · 技术社区  · 14 年前

    我见过一个函数名为 implicitly 在Scala示例中使用。它是什么,如何使用?

    Example here

    scala> sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo {
         |                         implicit def stringImpl = new Foo[String] {
         |                             def apply(list : List[String]) = println("String")
         |                         }
         |                         implicit def intImpl = new Foo[Int] {
         |                             def apply(list : List[Int]) =  println("Int")
         |                         }
         |                     } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
    defined trait Foo
    defined module Foo
    foo: [A](x: List[A])(implicit evidence$1: Foo[A])Unit
    
    scala> foo(1)
    <console>:8: error: type mismatch;
     found   : Int(1)
     required: List[?]
           foo(1)
               ^
    scala> foo(List(1,2,3))
    Int
    scala> foo(List("a","b","c"))
    String
    scala> foo(List(1.0))
    <console>:8: error: could not find implicit value for evidence parameter of type
     Foo[Double]
           foo(List(1.0))
              ^
    

    请注意,我们必须 implicitly[Foo[A]].apply(x) 因为编译器认为 implicitly[Foo[A]](x) 意味着我们打电话 含蓄地 带参数。

    另请参见 How to investigate objects/types/etc. from Scala REPL? Where does Scala look for implicits?

    3 回复  |  直到 7 年前
        1
  •  208
  •   retronym    13 年前

    implicitly

    理解/排除隐式视图

    当选择的前缀(例如, the.prefix.selection(args) 不包含成员 selection 适用于 args 参数 隐式视图)。在这种情况下,编译器将查找隐式成员,这些成员是在当前或封闭作用域中本地定义的、继承的或导入的,或者是来自该作用域类型的函数 the.prefix 到一个有 选择 定义的或等效的隐式方法。

    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
    

    当表达式不符合预期类型时,也可以触发隐式视图,如下所示:

    scala> 1: scala.runtime.RichInt
    res25: scala.runtime.RichInt = 1
    

    编译器在此处查找此函数:

    scala> implicitly[Int => scala.runtime.RichInt]
    res26: (Int) => scala.runtime.RichInt = <function1>
    

    隐式参数可以说是Scala比隐式视图更重要的特性。它们支持类型类模式。标准库在一些地方使用了这种方法--请参见 scala.Ordering SeqLike#sorted . 隐式参数还用于传递数组清单,以及 CanBuildFrom 实例。

    A 需要类型为的隐式参数 M[A] :

    def foo[A](implicit ma: M[A])
    

    可以重写为:

    def foo[A: M]
    

    但是传递隐式参数而不命名又有什么意义呢?这在实现方法时有什么用处 foo

    含蓄地 要实现价值:

    def foo[A: M] = {
       val ma = implicitly[M[A]]
    }
    

    假设您正在使用基于类型类的方法调用一个方法来打印一个人:

    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)
    

    PersonShow ,显式传递替代项 Show[String] Show[Int]

    Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)
    
        2
  •  217
  •   Jeffrey Chung    7 年前

    Implicitly 在Scala 2.8中可用,并在中定义 Predef 作为:

    def implicitly[T](implicit e: T): T = e
    

    它通常用于 检查是否存在隐式 类型 T 有货就退货 如果是这样的话。

    retronym's presentation :

    scala> implicit val a = "test" // define an implicit value of type String
    a: java.lang.String = test
    scala> val b = implicitly[String] // search for an implicit value of type String and assign it to b
    b: String = test
    scala> val c = implicitly[Int] // search for an implicit value of type Int and assign it to c
    <console>:6: error: could not find implicit value for parameter e: Int
           val c = implicitly[Int]
                             ^
    
        3
  •  -3
  •   Randall Schulz    14 年前

    一个“教你钓鱼”的答案是使用的字母成员索引,目前可在 Scaladoc nightlies . 字母(和 # ,对于非字母名称)在包/类窗格的顶部是指向以该字母开头的成员名称索引的链接(跨所有类)。如果你愿意 I ,例如,你会发现 implicitly 出现一次的条目,在 Predef ,您可以从那里的链接访问。