我一直在工作与斯卡拉了一段时间,已经写了10,000行程序与它,但我仍然被一些内部运作的混淆。 我来到斯卡拉在Python已经有使用Java,C和Lisp亲密熟悉之后,但即便如此,它一直进展缓慢,和一个巨大的问题是令人沮丧的困难,试图调查对象/类型的内部工作时,我经常发现/类/等。 使用的Scala REPL作为与Python比较。 在Python中,你可以调查任何对象foo
(类型,对象在一个全局变量,内置功能等)使用foo
,看看有什么东西的计算结果为, type(foo)
,以显示它的类型, dir(foo)
告诉你可以在其上调用的方法,并help(foo)
获得了内置的文档。 你甚至可以做这样的事情help("re")
找出在指定包的文档re
(持有正则表达式对象和方法),即使没有与它相关联的对象。
在Scala中,你可以尝试阅读在线文档,去查查源代码库,等等,但是这往往是对的事情非常困难的,你不知道,它是经常在那里,甚至它们是什么(一大块咬掉,考虑到庞大的类型层次) -东西在不同的地方周围浮动(包scala
, Predef
,各种隐式转换,像符号::
是几乎不可能谷歌)。 该REPL应直接探路,但在现实中,事情是更加神秘。 说,我已经看到了参考foo
地方,但我不知道它是什么。 有很明显的没有这样的事情“指南,系统地调查斯卡拉一样的东西与REPL”,但下面是试错大量后我所拼凑起来:
- 如果
foo
是一个值(这大概包括存储在变量加伴侣对象和其他斯卡拉事情object
S),你可以评估foo
直接。 这应该告诉你结果的类型和价值。 有时候,结果是有帮助的,有时没有。 - 如果
foo
是一个值,你可以使用:type foo
来获得它的类型。 (不一定启发。)如果你使用这个在函数调用,你得到的返回值的类型,而不是调用它。 - 如果
foo
是一个值,你可以使用foo.getClass
得到它的类。 (通常,比以前更具启发性,但如何对象的类从它的类型有什么不同?) - 对于一类
foo
,您可以使用classOf[foo]
,虽然不是很明显的结果意味着什么。 - 从理论上讲,你可以使用
:javap foo
拆开一类-这应该是最有用的是,但完全并均匀地失败对我来说。 - 有时候,你必须从错误信息拼凑的东西放在一起。
使用故障的例子:javap
scala> :javap List
Failed: Could not find class bytes for 'List'
启发错误消息的示例:
scala> assert
<console>:8: error: ambiguous reference to overloaded definition,
both method assert in object Predef of type (assertion: Boolean, message: => Any)Unit
and method assert in object Predef of type (assertion: Boolean)Unit
match expected type ?
assert
^
好了,现在让我们尝试一个简单的例子。
scala> 5
res63: Int = 5
scala> :type 5
Int
scala> 5.getClass
res64: java.lang.Class[Int] = int
够简单...
现在,让我们尝试一些真实的情况下,如果它不是那么明显:
scala> Predef
res65: type = scala.Predef$@3cd41115
scala> :type Predef
type
scala> Predef.getClass
res66: java.lang.Class[_ <: object Predef] = class scala.Predef$
这是什么意思? 为什么类型Predef
简单地type
,而类是scala.Predef$
? 我收集了$是同伴对象被硬塞到Java的方式......但在谷歌文档斯卡拉告诉我Predef
是object Predef extends LowPriorityImplicits
-我怎么可以推断这从REPL? 我怎么可以看看里面有什么?
OK,让我们尝试另一种困惑的事情:
scala> `::`
res77: collection.immutable.::.type = ::
scala> :type `::`
collection.immutable.::.type
scala> `::`.getClass
res79: java.lang.Class[_ <: object scala.collection.immutable.::] = class scala.collection.immutable.$colon$colon$
scala> classOf[`::`]
<console>:8: error: type :: takes type parameters
classOf[`::`]
^
scala> classOf[`::`[Int]]
res81: java.lang.Class[::[Int]] = class scala.collection.immutable.$colon$colon
OK,这让我绝望迷茫,最终,我不得不去阅读源代码,以使这一切的感觉。
所以,我的问题是:
- 什么是从使用REPL使Scala的对象,类,方法等的意识的真正斯卡拉专家建议最好的办法,或者至少他们调查是最好的,可以从REPL做些什么呢?
- 如何获取
:javap
从REPL工作内置的东西? (难道不应该在默认情况下工作吗?)
感谢您的任何启示。
你刚才提到这斯卡拉缺少一点很重要的一点:文档。
该REPL是一个奇妙的工具,但它并不像梦幻般的在它可以。 有太多缺少的功能和特性,可改善 - 其中一些是在您的文章中提到。 Scaladoc是一个很好的工具,也不过是远是完美的。 此外大量的API代码是没有或过少文档和代码示例经常丢失。 该IDE是完全OB错误和相比可能的Java IDE告诉我们他们喜欢看一些幼儿园的玩具。
不过有一种比较可用的工具,因为我开始2 - 3年前学习斯卡拉Scalas当前工具一个巨大的差异。 在后台编译永久一些垃圾那时的IDE,编译器每隔几分钟崩溃和一些文档是绝对不存在的。 通常我愤怒的攻击,并祝愿死亡和腐败Scala的作者。
现在? 我没有任何这些愤怒的攻击了。 因为我们目前拥有的工具是伟大的虽然是不完美的!
有docs.scala-lang.org ,它总结了很多伟大的文档。 有教程,小抄,词汇表,指南和很多更伟大的东西。 另一位伟大的工具是将scaleX ,它可以找到,甚至怪异的运营商一个能想到的。 这是Scalas Hoogle即使它还不如他的伟大理想,因为好,这是非常有用的。
大的改善与Scala2.10进来Scalas自己的倒影库的形式:
// needs Scala2.10M4
scala> import scala.reflect.runtime.{universe => u}
import scala.reflect.runtime.{universe=>u}
scala> val t = u.typeOf[List[_]]
t: reflect.runtime.universe.Type = List[Any]
scala> t.declarations
res10: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(constructor List, method companion, method isEmpty, method head, method tail, method ::, method :::, method reverse_:::, method mapConserve, method ++, method +:, method toList, method take, method drop, method slice, method takeRight, method splitAt, method takeWhile, method dropWhile, method span, method reverse, method stringPrefix, method toStream, method removeDuplicates)
新思考图书馆的文献信息仍然缺失,但在进步。 它允许人们在REPL里面一个简单的方法使用scalac:
scala> u reify { List(1,2,3) map (_+1) }
res14: reflect.runtime.universe.Expr[List[Int]] = Expr[List[Int]](immutable.this.List.apply(1, 2, 3).map(((x$1) => x$1.$plus(1)))(immutable.this.List.canBuildFrom))
scala> import scala.tools.reflect.ToolBox
import scala.tools.reflect.ToolBox
scala> import scala.reflect.runtime.{currentMirror => m}
import scala.reflect.runtime.{currentMirror=>m}
scala> val tb = m.mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@32f7fa37
scala> tb.parseExpr("List(1,2,3) map (_+1)")
res16: tb.u.Tree = List(1, 2, 3).map(((x$1) => x$1.$plus(1)))
scala> tb.runExpr(res16)
res18: Any = List(2, 3, 4)
这是当我们想知道如何Scala代码在内部被翻译更大。 以前文需要键入scala -Xprint:typer -e "List(1,2,3) map (_+1)"
来获取内部表示。 此外发现了一些小的改进有到新版本的方式,例如:
scala> :type Predef
scala.Predef.type
Scaladoc会获得一些类型层次图 (点击式的层次结构)。
用宏现在是可能的,在一个伟大的方式来提高错误消息。 有一个叫库expecty ,它做到这一点:
// copied from GitHub page
import org.expecty.Expecty
case class Person(name: String = "Fred", age: Int = 42) {
def say(words: String*) = words.mkString(" ")
}
val person = Person()
val expect = new Expecty()
// Passing expectations
expect {
person.name == "Fred"
person.age * 2 == 84
person.say("Hi", "from", "Expecty!") == "Hi from Expecty!"
}
// Failing expectation
val word1 = "ping"
val word2 = "pong"
expect {
person.say(word1, word2) == "pong pong"
}
/*
Output:
java.lang.AssertionError:
person.say(word1, word2) == "pong pong"
| | | | |
| | ping pong false
| ping pong
Person(Fred,42)
*/
有一个工具,它允许一个找到托管在GitHub库,称为ls.implicit.ly 。
所述集成开发环境现在有一些语义突出显示,以显示如果一个成员是对象/类型/方法/不管。 的语义突出显示功能ScalaIDE 。
在REPL的javap的功能仅适用于本地的javap一个电话,所以它不是一个非常丰富的featue工具。 你必须完全限定一个模块的名称:
scala> :javap scala.collection.immutable.List
Compiled from "List.scala"
public abstract class scala.collection.immutable.List extends scala.collection.AbstractSeq implements scala.collection.immutable.LinearSeq,scala.Product,scala.collection.LinearSeqOptimized{
...
前一段时间我写了一个的Scala代码是如何编译成字节码汇总 ,它提供了很多的东西就知道了。
而最好的:这是所有在过去几个月完成了!
那么,如何使用所有这些东西的REPL里面? 嗯,这是不可能的......还没有。 ;)
但我可以告诉你,有一天我们都会有这样的REPL。 一个REPL这说明我们的文档,如果我们希望看到它。 一个REPL这让我们与它通信(也许像lambdabot )。 一个REPL这让我们这样做很酷的事情,我们还是无法想象的。 我不知道什么时候这将是如此,但我知道,很多东西在过去几年做了,并且我知道,更大的东西将在未来几年完成。
javap的工作,但你将其指向scala.Predef.List
,这是一个type
,而不是一个class
。 它指向而不是scala.collection.immutable.List
。
现在,大部分只是输入一个数值,看到的结果的类型是什么,是不够的。 使用:type
可以是有帮助的时候。 我发现,使用getClass
是绕了一个非常糟糕的方式,虽然。
此外,你有时会混合类型和值。 例如,在这里你参考对象::
:
scala> `::`.getClass res79: java.lang.Class[_ <: object
scala.collection.immutable.::] = class
scala.collection.immutable.$colon$colon$
在这里,你指的是类::
:
scala> classOf[`::`[Int]] res81: java.lang.Class[::[Int]] = class
scala.collection.immutable.$colon$colon
对象和类是不一样的东西,而且,事实上,有同名对象和类的一个常见的模式,与他们的关系的具体名称:同伴。
取而代之的dir
,只需使用制表符完成:
scala> "abc".
+ asInstanceOf charAt codePointAt codePointBefore codePointCount
compareTo compareToIgnoreCase concat contains contentEquals endsWith
equalsIgnoreCase getBytes getChars indexOf intern isEmpty
isInstanceOf lastIndexOf length matches offsetByCodePoints regionMatches
replace replaceAll replaceFirst split startsWith subSequence
substring toCharArray toLowerCase toString toUpperCase trim
scala> "abc".compareTo
compareTo compareToIgnoreCase
scala> "abc".compareTo
def compareTo(String): Int
如果输入功率模式下,你会收获更多的信息,但是这很难说是初学者。 以上示出了类型,方法和方法签名。 javap的将反编译的东西,虽然这需要你对字节码良好的处理。
那里面有其他的东西-一定要认准了:help
,看看有什么可用。
文档是只能通过scaladoc API。 保持打开浏览器,并使用它的搜索功能快速查找类和方法。 另外,还要注意,而不是Java的,你不需要通过继承列表导航来获取方法的描述。
和他们做搜索符号完美的罚款。 我怀疑你没有花太多时间在scaladoc因为其他的文档工具,在那里只是没有达到它。 的Javadoc想到 - 这是通过包和类可怕的浏览。
如果您有具体问题堆栈溢出的风格,用符号猎犬的符号进行搜索。
使用夜间 Scaladocs:他们会从任何版本使用的是分歧,但他们永远是最完整的。 此外,现在他们在许多方面远远好:您可以使用选项卡上的搜索框帧之间交替,支持自动对焦,可以使用箭头滤波后的左帧上进行浏览和ENTER有选择的元素出现在正确的框架上。 他们有一个隐含的方法的列表,并有类图。
我做了做一个远不如强大的REPL,和远较差Scaladoc - 他们做的工作,共同提高。 当然,我跳过干路(现HEAD)只是为了得到我的手制表完成。
需要注意的是在斯卡拉REPL斯卡拉2.11.8新标签完成可以方便的类型探索/发现。
现在包括:
驼峰完成:
尝试:
(l: List[Int]).rro
TAB,
它扩展为:
(l: List[Int]).reduceRightOption
查找键入名称的任何部分驼峰成员:
尝试:
classOf[String].typ
TAB,让getAnnotationsByType
, getComponentType
及其他
全豆干将,而无需输入得到:
尝试:
(d: java.util.Date).day
TAB
按TAB键两次来查看方法签名:
尝试:
List(1,2,3).part
TAB,
其中完成对:
List(1,2,3).partition
;
再次按TAB键显示:
def partition(p: Int => Boolean): (List[Int], List[Int])
你需要完全限定类名传递给javap
。
首先把它用classOf
:
scala> classOf[List[_]]
res2: java.lang.Class[List[_]] = class scala.collection.immutable.List
然后使用javap
(不从REPL工作对我来说:“:javap的不可用这个平台上”),这样的例子是在命令行中,REPL,我相信,你并不需要指定类路径:
d:\bin\scala\scala-2.9.1-1\lib>javap -classpath scala-library.jar "scala.collection.immutable.List"
但我怀疑这会帮助你。 也许你正在尝试使用您在使用动态语言的使用技巧。 我非常很少使用Scala的REPL(而在JavaScript中经常使用它)。 一个IDE和来源都是我的。
文章来源: How to investigate objects/types/etc. from Scala REPL?