Wil*_*urn 85
好的,我不得不再添加一个.RegexScala中的每个对象都有一个提取器(参见上面的oxbox_lakes的答案),可以访问匹配组.所以你可以这样做:
// Regex to split a date in the format Y/M/D.
val regex = "(\\d+)/(\\d+)/(\\d+)".r
val regex(year, month, day) = "2010/1/13"
Run Code Online (Sandbox Code Playgroud)
如果您不习惯使用模式匹配和提取器,则第二行看起来很混乱.每当你定义一个val或者var,关键字之后的内容不仅仅是一个标识符,而是一个模式.这就是为什么这样做的原因:
val (a, b, c) = (1, 3.14159, "Hello, world")
Run Code Online (Sandbox Code Playgroud)
右手表达式创建了一个Tuple3[Int, Double, String]可以匹配模式的表达式(a, b, c).
大多数情况下,您的模式使用作为单例对象成员的提取器.例如,如果你写一个类似的模式
Some(value)
Run Code Online (Sandbox Code Playgroud)
然后你隐含地调用了提取器Some.unapply.
但是你也可以在模式中使用类实例,这就是这里发生的事情.val正则表达式是一个实例Regex,当你在一个模式中使用它时,你隐式调用regex.unapplySeq(unapply而unapplySeq不是超出了这个答案的范围),它将匹配组提取到a中Seq[String],其元素被分配以便变量年,月和日.
oxb*_*kes 51
结构类型定义 - 即通过它支持的方法描述的类型.例如:
object Closer {
def using(closeable: { def close(): Unit }, f: => Unit) {
try {
f
} finally { closeable.close }
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,除了具有方法之外,未定义参数的类型closeableclose
Apo*_*isp 45
例如,如果没有此功能,您可以表达在列表上映射函数以返回另一个列表,或在树上映射函数以返回另一个树的想法.但你不能表达这种想法通常不高于种.
使用更高类型,您可以捕获任何使用其他类型参数化的类型的想法.一个带有一个参数的类型构造函数被认为是实物(*->*).例如,List.返回另一个类型构造函数的类型构造函数被认为是实物(*->*->*).例如,Function1.但是在Scala中,我们有更高的类型,因此我们可以使用其他类型构造函数进行参数化的类型构造函数.所以他们就像((*->*)->*).
例如:
trait Functor[F[_]] {
def fmap[A, B](f: A => B, fa: F[A]): F[B]
}
Run Code Online (Sandbox Code Playgroud)
现在,如果你有Functor[List],你可以映射列表.如果你有Functor[Tree],你可以映射树木.但更重要的是,如果你有Functor[A] 任何A类(*->*),你可以映射一个函数A.
oxb*_*kes 39
提取器,允许您if-elseif-else用模式替换凌乱的样式代码.我知道这些并没有被完全隐藏,但我已经使用Scala几个月而没有真正理解它们的力量.对于(很长)的例子,我可以替换:
val code: String = ...
val ps: ProductService = ...
var p: Product = null
if (code.endsWith("=")) {
p = ps.findCash(code.substring(0, 3)) //e.g. USD=, GBP= etc
}
else if (code.endsWith(".FWD")) {
//e.g. GBP20090625.FWD
p = ps.findForward(code.substring(0,3), code.substring(3, 9))
}
else {
p = ps.lookupProductByRic(code)
}
Run Code Online (Sandbox Code Playgroud)
有了这个,我认为这更加清晰
implicit val ps: ProductService = ...
val p = code match {
case SyntheticCodes.Cash(c) => c
case SyntheticCodes.Forward(f) => f
case _ => ps.lookupProductByRic(code)
}
Run Code Online (Sandbox Code Playgroud)
我必须在后台做一些腿部工作......
object SyntheticCodes {
// Synthetic Code for a CashProduct
object Cash extends (CashProduct => String) {
def apply(p: CashProduct) = p.currency.name + "="
//EXTRACTOR
def unapply(s: String)(implicit ps: ProductService): Option[CashProduct] = {
if (s.endsWith("=")
Some(ps.findCash(s.substring(0,3)))
else None
}
}
//Synthetic Code for a ForwardProduct
object Forward extends (ForwardProduct => String) {
def apply(p: ForwardProduct) = p.currency.name + p.date.toString + ".FWD"
//EXTRACTOR
def unapply(s: String)(implicit ps: ProductService): Option[ForwardProduct] = {
if (s.endsWith(".FWD")
Some(ps.findForward(s.substring(0,3), s.substring(3, 9))
else None
}
}
Run Code Online (Sandbox Code Playgroud)
但是,由于它将一块业务逻辑分离到一个合理的位置,所以腿部工作是值得的.我可以Product.getCode按如下方式实现我的方法..
class CashProduct {
def getCode = SyntheticCodes.Cash(this)
}
class ForwardProduct {
def getCode = SyntheticCodes.Forward(this)
}
Run Code Online (Sandbox Code Playgroud)
Aym*_*men 35
在scala 2.8中,您可以使用包scala.util.control.TailCalls(事实上它是蹦床)来使用尾递归方法.
一个例子:
def u(n:Int):TailRec[Int] = {
if (n==0) done(1)
else tailcall(v(n/2))
}
def v(n:Int):TailRec[Int] = {
if (n==0) done(5)
else tailcall(u(n-1))
}
val l=for(n<-0 to 5) yield (n,u(n).result,v(n).result)
println(l)
Run Code Online (Sandbox Code Playgroud)
Aar*_*rup 35
案例类自动混合Product trait,提供对字段的无类型索引访问,无需任何反射:
case class Person(name: String, age: Int)
val p = Person("Aaron", 28)
val name = p.productElement(0) // name = "Aaron": Any
val age = p.productElement(1) // age = 28: Any
val fields = p.productIterator.toList // fields = List[Any]("Aaron", 28)
Run Code Online (Sandbox Code Playgroud)
此功能还提供了一种更改toString方法输出的简化方法:
case class Person(name: String, age: Int) {
override def productPrefix = "person: "
}
// prints "person: (Aaron,28)" instead of "Person(Aaron, 28)"
println(Person("Aaron", 28))
Run Code Online (Sandbox Code Playgroud)
ped*_*rla 32
它并没有完全隐藏,但肯定是一个宣传不足的功能:scalac -Xprint.
作为使用说明,请考虑以下来源:
class A { "xx".r }
Run Code Online (Sandbox Code Playgroud)
使用scalac -Xprint:typer输出编译它:
package <empty> {
class A extends java.lang.Object with ScalaObject {
def this(): A = {
A.super.this();
()
};
scala.this.Predef.augmentString("xx").r
}
}
Run Code Online (Sandbox Code Playgroud)
注意scala.this.Predef.augmentString("xx").r,这是implicit def augmentStringPredef.scala中现在的应用.
scalac -Xprint:<phase>将在一些编译阶段后打印语法树.要查看可用的阶段,请使用scalac -Xshow-phases.
这是了解幕后发生的事情的好方法.
试试吧
case class X(a:Int,b:String)
使用typer阶段来真正感受它是多么有用.
Ale*_*tec 30
您可以定义自己的控制结构.它实际上只是函数和对象以及一些语法糖,但它们看起来和行为都像真实的东西.
例如,以下代码定义dont {...} unless (cond)和dont {...} until (cond):
def dont(code: => Unit) = new DontCommand(code)
class DontCommand(code: => Unit) {
def unless(condition: => Boolean) =
if (condition) code
def until(condition: => Boolean) = {
while (!condition) {}
code
}
}
Run Code Online (Sandbox Code Playgroud)
现在您可以执行以下操作:
/* This will only get executed if the condition is true */
dont {
println("Yep, 2 really is greater than 1.")
} unless (2 > 1)
/* Just a helper function */
var number = 0;
def nextNumber() = {
number += 1
println(number)
number
}
/* This will not be printed until the condition is met. */
dont {
println("Done counting to 5!")
} until (nextNumber() == 5)
Run Code Online (Sandbox Code Playgroud)
mis*_*tor 26
@switch Scala 2.8中的注释:
要应用于匹配表达式的注释.如果存在,编译器将验证匹配是否已编译为tableswitch或lookupswitch,如果它编译为一系列条件表达式,则发出错误.
例:
scala> val n = 3
n: Int = 3
scala> import annotation.switch
import annotation.switch
scala> val s = (n: @switch) match {
| case 3 => "Three"
| case _ => "NoThree"
| }
<console>:6: error: could not emit switch for @switch annotated match
val s = (n: @switch) match {
Run Code Online (Sandbox Code Playgroud)
rai*_*hoo 26
Dunno,如果这真的是隐藏的,但我发现它非常好.
采用2种类型参数的类型构造函数可以用中缀表示法编写
object Main {
class FooBar[A, B]
def main(args: Array[String]): Unit = {
var x: FooBar[Int, BigInt] = null
var y: Int FooBar BigInt = null
}
}
Run Code Online (Sandbox Code Playgroud)
Wil*_*urn 24
Scala 2.8引入了默认和命名参数,这使得Scala添加到案例类的新"复制"方法成为可能.如果你定义这个:
case class Foo(a: Int, b: Int, c: Int, ... z:Int)
Run Code Online (Sandbox Code Playgroud)
并且你想创建一个新的Foo,就像现有的Foo,只有不同的"n"值,那么你可以说:
foo.copy(n = 3)
Run Code Online (Sandbox Code Playgroud)
Aym*_*men 24
在scala 2.8中,您可以将@specialized添加到您的泛型类/方法中.这将为原始类型(扩展AnyVal)创建类的特殊版本,并节省不必要的装箱/拆箱的成本:
class Foo[@specialized T]...
您可以选择AnyVals的子集:
class Foo[@specialized(Int,Boolean) T]...
agi*_*all 23
你可以为函数指定一个按名称调用参数(EDITED:这与一个惰性参数不同!),直到函数使用它才会被评估(编辑:事实上,它每次都会被重新评估)用过的).有关详细信息,请参阅此faq
class Bar(i:Int) {
println("constructing bar " + i)
override def toString():String = {
"bar with value: " + i
}
}
// NOTE the => in the method declaration. It indicates a lazy paramter
def foo(x: => Bar) = {
println("foo called")
println("bar: " + x)
}
foo(new Bar(22))
/*
prints the following:
foo called
constructing bar 22
bar with value: 22
*/
Run Code Online (Sandbox Code Playgroud)
Adr*_*ian 23
扩展语言.我一直想在Java中做这样的事情(不可能).但在斯卡拉我可以:
def timed[T](thunk: => T) = {
val t1 = System.nanoTime
val ret = thunk
val time = System.nanoTime - t1
println("Executed in: " + time/1000000.0 + " millisec")
ret
}
Run Code Online (Sandbox Code Playgroud)
然后写:
val numbers = List(12, 42, 3, 11, 6, 3, 77, 44)
val sorted = timed { // "timed" is a new "keyword"!
numbers.sortWith(_<_)
}
println(sorted)
Run Code Online (Sandbox Code Playgroud)
得到
Executed in: 6.410311 millisec
List(3, 3, 6, 11, 12, 42, 44, 77)
Run Code Online (Sandbox Code Playgroud)
mis*_*tor 20
您可以使用locally引入本地块而不会导致分号推断问题.
用法:
scala> case class Dog(name: String) {
| def bark() {
| println("Bow Vow")
| }
| }
defined class Dog
scala> val d = Dog("Barnie")
d: Dog = Dog(Barnie)
scala> locally {
| import d._
| bark()
| bark()
| }
Bow Vow
Bow Vow
Run Code Online (Sandbox Code Playgroud)
locally 在"Predef.scala"中定义为:
@inline def locally[T](x: T): T = x
Run Code Online (Sandbox Code Playgroud)
作为内联,它不会产生任何额外的开销.
Eug*_*ota 17
匿名函数的占位符语法
来自Scala语言规范:
SimpleExpr1 ::= '_'
Run Code Online (Sandbox Code Playgroud)
表达式(语法类别
Expr)可以_在标识符合法的位置包含嵌入的下划线符号.这样的表达式表示匿名函数,其中下划线的后续出现表示连续的参数.
来自Scala语言更改:
_ + 1 x => x + 1
_ * _ (x1, x2) => x1 * x2
(_: Int) * 2 (x: Int) => x * 2
if (_) x else y z => if (z) x else y
_.map(f) x => x.map(f)
_.map(_ + 1) x => x.map(y => y + 1)
Run Code Online (Sandbox Code Playgroud)
使用它你可以做类似的事情:
def filesEnding(query: String) =
filesMatching(_.endsWith(query))
Run Code Online (Sandbox Code Playgroud)
mis*_*tor 17
trait AbstractT2 {
println("In AbstractT2:")
val value: Int
val inverse = 1.0/value
println("AbstractT2: value = "+value+", inverse = "+inverse)
}
val c2c = new {
// Only initializations are allowed in pre-init. blocks.
// println("In c2c:")
val value = 10
} with AbstractT2
println("c2c.value = "+c2c.value+", inverse = "+c2c.inverse)
Run Code Online (Sandbox Code Playgroud)
输出:
In AbstractT2:
AbstractT2: value = 10, inverse = 0.1
c2c.value = 10, inverse = 0.1
Run Code Online (Sandbox Code Playgroud)
我们实例化一个匿名内部类,
value在with AbstractT2子句之前初始化块中的字段.这保证了value在执行主体之前初始化AbstractT2,如运行脚本时所示.
rai*_*hoo 17
您可以使用'with'关键字组合结构类型
object Main {
type A = {def foo: Unit}
type B = {def bar: Unit}
type C = A with B
class myA {
def foo: Unit = println("myA.foo")
}
class myB {
def bar: Unit = println("myB.bar")
}
class myC extends myB {
def foo: Unit = println("myC.foo")
}
def main(args: Array[String]): Unit = {
val a: A = new myA
a.foo
val b: C = new myC
b.bar
b.foo
}
}
Run Code Online (Sandbox Code Playgroud)
Dan*_*ral 16
隐含定义,尤其是转换.
例如,假设一个函数将输入字符串格式化为适合大小,通过用"..."替换它的中间:
def sizeBoundedString(s: String, n: Int): String = {
if (n < 5 && n < s.length) throw new IllegalArgumentException
if (s.length > n) {
val trailLength = ((n - 3) / 2) min 3
val headLength = n - 3 - trailLength
s.substring(0, headLength)+"..."+s.substring(s.length - trailLength, s.length)
} else s
}
Run Code Online (Sandbox Code Playgroud)
您可以将它与任何String一起使用,当然,也可以使用toString方法转换任何内容.但你也可以像这样写:
def sizeBoundedString[T](s: T, n: Int)(implicit toStr: T => String): String = {
if (n < 5 && n < s.length) throw new IllegalArgumentException
if (s.length > n) {
val trailLength = ((n - 3) / 2) min 3
val headLength = n - 3 - trailLength
s.substring(0, headLength)+"..."+s.substring(s.length - trailLength, s.length)
} else s
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以通过执行以下操作传递其他类型的类:
implicit def double2String(d: Double) = d.toString
Run Code Online (Sandbox Code Playgroud)
现在你可以调用该函数传递一个double:
sizeBoundedString(12345.12345D, 8)
Run Code Online (Sandbox Code Playgroud)
最后一个参数是隐式的,并且由于隐式de声明而被自动传递.此外,"s"被视为 sizeBoundedString中的String,因为它有一个从它到String的隐式转换.
对于不常见的类型,可以更好地定义此类型的隐含,以避免意外转换.你也可以明确地传递一个转换,它仍然会在sizeBoundedString中隐式使用:
sizeBoundedString(1234567890L, 8)((l : Long) => l.toString)
Run Code Online (Sandbox Code Playgroud)
您也可以有多个隐式参数,但是您必须传递所有这些参数,或者不传递任何参数.隐式转换还有一种快捷语法:
def sizeBoundedString[T <% String](s: T, n: Int): String = {
if (n < 5 && n < s.length) throw new IllegalArgumentException
if (s.length > n) {
val trailLength = ((n - 3) / 2) min 3
val headLength = n - 3 - trailLength
s.substring(0, headLength)+"..."+s.substring(s.length - trailLength, s.length)
} else s
}
Run Code Online (Sandbox Code Playgroud)
这使用方式完全相同.
Implicits可以有任何价值.例如,它们可用于隐藏库信息.以下面的示例为例:
case class Daemon(name: String) {
def log(msg: String) = println(name+": "+msg)
}
object DefaultDaemon extends Daemon("Default")
trait Logger {
private var logd: Option[Daemon] = None
implicit def daemon: Daemon = logd getOrElse DefaultDaemon
def logTo(daemon: Daemon) =
if (logd == None) logd = Some(daemon)
else throw new IllegalArgumentException
def log(msg: String)(implicit daemon: Daemon) = daemon.log(msg)
}
class X extends Logger {
logTo(Daemon("X Daemon"))
def f = {
log("f called")
println("Stuff")
}
def g = {
log("g called")(DefaultDaemon)
}
}
class Y extends Logger {
def f = {
log("f called")
println("Stuff")
}
}
Run Code Online (Sandbox Code Playgroud)
在此示例中,在Y对象中调用"f"将日志发送到默认守护程序,并在X的实例上发送到守护程序X守护程序.但是在X的实例上调用g会将日志发送到明确给定的DefaultDaemon.
虽然这个简单的例子可以用重载和私有状态重写,但implicits不需要私有状态,并且可以通过导入进入上下文.
agi*_*all 13
也许不是太隐蔽,但我认为这很有用:
@scala.reflect.BeanProperty
var firstName:String = _
Run Code Online (Sandbox Code Playgroud)
这将自动为与bean约定匹配的字段生成getter和setter.
developerworks上的进一步描述
axe*_*l22 13
闭包中的隐含参数.
函数参数可以像方法一样标记为隐式.在函数体内的范围内,隐式参数是可见的,并且有资格进行隐式解析:
trait Foo { def bar }
trait Base {
def callBar(implicit foo: Foo) = foo.bar
}
object Test extends Base {
val f: Foo => Unit = { implicit foo =>
callBar
}
def test = f(new Foo {
def bar = println("Hello")
})
}
Run Code Online (Sandbox Code Playgroud)
Aym*_*men 12
使用Scala构建无限数据结构Stream:http:
//www.codecommit.com/blog/scala/infinite-lists-for-the-finitely-patient
jsu*_*eth 12
结果类型取决于隐式解析.这可以为您提供多种发送方式:
scala> trait PerformFunc[A,B] { def perform(a : A) : B }
defined trait PerformFunc
scala> implicit val stringToInt = new PerformFunc[String,Int] {
def perform(a : String) = 5
}
stringToInt: java.lang.Object with PerformFunc[String,Int] = $anon$1@13ccf137
scala> implicit val intToDouble = new PerformFunc[Int,Double] {
def perform(a : Int) = 1.0
}
intToDouble: java.lang.Object with PerformFunc[Int,Double] = $anon$1@74e551a4
scala> def foo[A, B](x : A)(implicit z : PerformFunc[A,B]) : B = z.perform(x)
foo: [A,B](x: A)(implicit z: PerformFunc[A,B])B
scala> foo("HAI")
res16: Int = 5
scala> foo(1)
res17: Double = 1.0
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
52335 次 |
| 最近记录: |