什么是Scala标识符;含蓄地;?
我在Scala示例中看到了一个名为什么是Scala标识符;含蓄地;?,scala,implicits,Scala,Implicits,我在Scala示例中看到了一个名为的隐式函数。它是什么,如何使用 : scala>Foo[T]{def apply(list:list[T]):Unit};对象Foo{ |隐式def stringImpl=new Foo[String]{ |def apply(list:list[String])=println(“String”) | } |隐式def intImpl=new Foo[Int]{ |def应用(列表:列表[Int])=printl
的隐式函数。它是什么,如何使用
:
scala>Foo[T]{def apply(list:list[T]):Unit};对象Foo{
|隐式def stringImpl=new Foo[String]{
|def apply(list:list[String])=println(“String”)
| }
|隐式def intImpl=new Foo[Int]{
|def应用(列表:列表[Int])=println(“Int”)
| }
| } ; def foo[A:foo](x:List[A])=隐式[foo[A]]。应用(x)
定义特征Foo
定义模块Foo
foo[A](x:List[A])(隐含证据$1:foo[A])单位
scala>foo(1)
:8:错误:类型不匹配;
发现:Int(1)
必填项:列表[?]
傅(1)
^
scala>foo(列表(1,2,3))
Int
scala>foo(列表(“a”、“b”、“c”))
一串
scala>foo(列表(1.0))
:8:错误:找不到类型为的证据参数的隐式值
福[双]
foo(列表(1.0))
^
注意,我们必须隐式地编写Foo[A]]。apply(x)
,因为编译器认为隐式地[Foo[A]](x)
意味着我们使用参数隐式地调用
另请参见和隐式
在Scala 2.8中可用,并在中定义为:
它通常用于检查类型为T
的隐式值是否可用,如果可用,则返回它
以下是一个简单的例子:
scala>implicit val a=“test”//定义字符串类型的隐式值
a:java.lang.String=test
scala>val b=implicitly[String]//搜索String类型的隐式值并将其分配给b
b:字符串=测试
scala>val c=implicitly[Int]//搜索Int类型的隐式值并将其分配给c
:6:错误:找不到参数e:Int的隐式值
val c=隐式[Int]
^
一个“教你钓鱼”的答案是使用网站上当前可用的字母索引。“包/类”窗格顶部的字母(以及非字母名称的#
)是指向以该字母开头的成员名称索引的链接(在所有类中)。例如,如果您选择I
,您将在Predef
中找到一个出现的隐式
条目,您可以从那里的链接访问该条目。以下是使用非常简单的方法隐式
的几个原因
理解/排除隐式视图的步骤
当选择的前缀(例如,the.prefix.selection(args)
不包含适用于args
的成员selection
(即使尝试使用隐式视图转换args
)时,也会触发隐式视图。在这种情况下,编译器将查找在当前或封闭作用域中本地定义、继承或导入的隐式成员,这些成员是从.prefix
类型到定义了selection
类型的函数,或等效的隐式方法
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> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>
可以重写为:
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)
隐式启动Scala 3已被改进的召唤所取代,其优点是能够返回比要求更多的
call
方法隐式地对应于Scala 2中的
与“不成形”中的方法完全相同。不同之处在于
在召唤
(或)和之间隐含地
是,召唤可以返回
比要求的类型更精确的类型
例如,给定以下类型
trait F[In]:
type Out
def f(v: Int): Out
given F[Int] with
type Out = String
def f(v: Int): String = v.toString
隐式地
方法将调用具有已擦除类型成员的术语Out
scala> implicitly[F[Int]]
val res5: F[Int] = given_F_Int$@7d0e5fbb
scala> implicitly[res5.Out =:= String]
1 |implicitly[res5.Out =:= String]
| ^
| Cannot prove that res5.Out =:= String.
scala> val x: res5.Out = ""
1 |val x: res5.Out = ""
| ^^
| Found: ("" : String)
| Required: res5.Out
为了恢复类型成员,我们必须显式地引用它,这违背了使用类型成员而不是类型参数的目的
scala> implicitly[F[Int] { type Out = String }]
val res6: F[Int]{Out = String} = given_F_Int$@7d0e5fbb
scala> implicitly[res6.Out =:= String]
val res7: res6.Out =:= String = generalized constraint
但定义为
def summon[T](using inline x: T): x.type = x
没有这个问题
scala> summon[F[Int]]
val res8: given_F_Int.type = given_F_Int$@7d0e5fbb
scala> summon[res8.Out =:= String]
val res9: String =:= String = generalized constraint
scala> val x: res8.Out = ""
val x: res8.Out = ""
我们看到类型成员type Out=String
没有被删除,即使我们只要求F[Int]
而不是F[Int]{type Out=String}
。这可以证明在以下情况下特别相关:
由隐式调用的类型没有Out
类型成员。对于此
因此,在处理依赖类型时,我们应该避免隐式
功能
当然,那些scaladocs根本没有提到隐式,所以这几乎算不上文档。有人如何从这些文档中找出该方法的作用呢?我经常对Scala文档感到失望。隐式等方法的行为远非显而易见,它们的文档也仅仅比不存在。感谢上帝,堆栈溢出。/endrant@Jeff很好地查看了这一个类型签名文档。隐式
似乎是Scala中一个重要的语言特性,绝对值得适当解释
trait F[In]:
type Out
def f(v: Int): Out
given F[Int] with
type Out = String
def f(v: Int): String = v.toString
scala> implicitly[F[Int]]
val res5: F[Int] = given_F_Int$@7d0e5fbb
scala> implicitly[res5.Out =:= String]
1 |implicitly[res5.Out =:= String]
| ^
| Cannot prove that res5.Out =:= String.
scala> val x: res5.Out = ""
1 |val x: res5.Out = ""
| ^^
| Found: ("" : String)
| Required: res5.Out
scala> implicitly[F[Int] { type Out = String }]
val res6: F[Int]{Out = String} = given_F_Int$@7d0e5fbb
scala> implicitly[res6.Out =:= String]
val res7: res6.Out =:= String = generalized constraint
def summon[T](using inline x: T): x.type = x
scala> summon[F[Int]]
val res8: given_F_Int.type = given_F_Int$@7d0e5fbb
scala> summon[res8.Out =:= String]
val res9: String =:= String = generalized constraint
scala> val x: res8.Out = ""
val x: res8.Out = ""