关闭

Scala简明教程(3)

标签: scala面向对象基础教程
374人阅读 评论(0) 收藏 举报
分类:

Scala简明教程(3)

面向对象
没有访问修饰符的class或者类成员默认都是public类型的

参数是private类型

class C(x: R) //等价于
class C(private val x: R)
var c = new C(4)

参数是public类型

class C(val x: R)
var c = new C(4)
c.x

final和sealed
对于内部类, inst1.InnerClass1 和inst2.InnerClass1是不同的类型,这和Java不一样。 如果想使用相同的类型,使用Class#InnerClass1

class C(var x: R) {
assert(x > 0, "positive please") //constructor is class body,所以你可以在这里写一些语句
var y = x  //public成员
val readonly = 5 //只能读取,无法set
private var secret = 1 //private成员
def this = this(42) //其它构造函数
}
new{ ... }
abstract class D { ... }
class C extends D { ... }  //继承
class D(var x: R)
class C(x: R) extends D(x)  //继承和构造函数参数. (wishlist: automatically pass-up params by default)
object O extends D { ... }  //object定义单例
trait T { ... } //traits.
class C extends T { ... } //实现接口. no constructor params. mixin-able.
class C extends D with T { ... }
trait T1; trait T2 //多个traits
class C extends T1 with T2
class C extends D with T1 with T2 
class C extends D { override def f = ...} //必须声明override
new java.io.File("f")  //产生类对象
List(1,2,3)  
classOf[String] //类字面值 
x.isInstanceOf[String] //运行时检查
x.asInstanceOf[String] //运行时cast
x: String //编译时指明
final class A{
  final val x = 1
  var y = 2
}
sealed class B

泛型
方法带类型参数

def mapmake[T](g:T=>T)(seq: List[T]) = seq.map(g)

类带类型参数

class Stack[T] {
var elems: List[T] = Nil
def push(x: T) { elems = x :: elems }
def top: T = elems.head
def pop() { elems = elems.tail }
}

Lower Type Bounds

<p>class A
class B extends A
def test[T <: A](t: T) = {}
test(new A)
test(new B) //error
Upper Type Bounds
class A
class B extends A
class C extends B
def test[T <: A](t: T) = {}
test[A](new A)
test[C](new C) //error</p>

covariant 针对类

class Test[+T](x: T)

invariant

class A
class B extends A
class C extends B
class Test[T](x: T)
val c = new Test(new C)
val t:Test[B] = c //Note: C <: B, but class Test is invariant in type T. You may wish to define T as +T instead. (SLS 4.5)
val a = new Test(new A)
val t:Test[B] = a //Note: A >: B, but class Test is invariant in type. You may wish to define T as -T instead. (SLS 4.5)

contravariant 针对类

class Test[-T](x: T)

总结:
1) 协变
[+T], covariant (or “flexible”) in its type parameter T,类似Java中的(? extends T), 即可以用T和T的子类来替换T,里氏替换原则。
2) 不变
不支持T的子类或者父类,只知支持T本身。
3) 逆变
[-T], contravariant, 类似(? supers T) 只能用T的父类来替换T。是逆里氏替换原则。
4) 上界
只允许T的超类U来替换T。 [U >: T]
5) 下界
只允许T的子类U来替代T。 [U <: T]

注解

@interface SourceURL {
public String value();
public String mail() default "";
}

使用

@interface Source {
public String URL();
public String mail();
}

@Source(URL = "http://coders.com/",
mail = "support@coders.com")
class MyScalaClass ...

简写(对于属性名为value的特殊属性)

@interface SourceURL {
   public String value();
   public String mail() default "";
   }
   @SourceURL("http://coders.com/")
class MyScalaClass ..
@SourceURL("http://coders.com/",
mail = "support@coders.com")
class MyScalaClass .

Implicit
implicit parameters 隐式参数
如果参数定义为implicit,那么在调用的如果没设置, 那么参数会自动提供。
隐式参数与缺省参数是完全不一样的。缺省参数是函数定义方设定了一个缺省值,在调用者没有指明时将使用该缺省值。 隐式参数则不同,最终是会由调用方指定参数值,只是不一定在调用的语句里指定而已。编译器在发现缺少隐式参数时,会在程序范围内寻找符合类型的隐式值,如果找不到则编译会失败。

abstract class Logger {def log(s: String)}
class FileLogger extends Logger {
  def log(s: String) {println("Log in file: " + s)}
}
class StdoutLogger extends Logger {
  def log(s: String) {println("Stdout: " + s)}
}
def Add(a: Int, b: Int)(implicit logger: Logger) {
  val sum = a + b
  logger.log("%d + %d = %d".format(a, b, sum ))
}
implicit val log = new FileLogger
Add(1,2)
Add(2,3)(new StdoutLogger) //you may do it explicitly

如果上述代码没有implicit val log = new FileLogger这一句,在代码范围内也没有其他的Logger类型的implicit值,编译器会报错.
反之,如果能找到Logger类型的隐式值,编译器会将该隐式值作为参数传递过去。
implicit class 隐式类
A new language construct is proposed to simplify the creation of classes which provide extension methods to another type.

implicit class RichInt(n: Int) extends Ordered[Int] {
def min(m: Int): Int = if (n <= m) n else m
...
}

被转换为

class RichInt(n: Int) extends Ordered[Int] {
def min(m: Int): Int = if (n <= m) n else m
...
}
implicit final def RichInt(n: Int): RichInt = new RichInt(n)

implicit method 隐式转换
有时候,你并不需要指定一个类型是等/子/超于另一个类,你可以通过转换这个类来伪装这种关联关系。一个视界指定一个类型可以被“看作是”另一个类型。这对对象的只读操作是很有用的。
隐函数允许类型自动转换。更确切地说,在隐式函数可以帮助满足类型推断时,它们允许按需的函数应用。例如:

implicit def strToInt(x: String) = x.toInt
val y: Int = "123"

view
view,就像类型边界,要求对给定的类型存在这样一个函数。您可以使用<%指定类型限制,例如:

class Container[A <% Int] { def addIt(x: A) = 123 + x }

这是说 A 必须“可被视”为 Int 。
方法可以通过隐含参数执行更复杂的类型限制。例如,List支持对数字内容执行sum,但对其他内容却不行。可是Scala的数字类型并不都共享一个超类,所以我们不能使用T <: Number。相反,要使之能工作,Scala的math库对适当的类型T 定义了一个隐含的Numeric[T]。 然后在List定义中使用它:

sum[B >: A](implicit num: Numeric[B]): B

如果你调用List(1,2).sum(),你并不需要传入一个 num 参数;它是隐式设置的。但如果你调用List(“whoop”).sum(),它会抱怨无法设置num。
在没有设定陌生的对象为Numeric的时候,方法可能会要求某种特定类型的“证据”。这时可以使用以下类型-关系运算符:

A =:= B A 必须和 B相等
A <:< B A 必须是 B的子类
A <%< B A 必须可以被看做是 B
class Container[A](value: A) { def addIt(implicit evidence: A =:= Int) = 123 + value }

空对象Nil,Null,null,Unit,Nothing,None
1) Nothing 是trait,定义为:final trait Nothing extends Any。Nothing处于Scala类型体系的最底层,是所有类型的子类型,Nothing没有实例。
2) Null 是trait,定义为:final trait Null extends AnyRef 。Null是所有引用类型的子类型,唯一的一个实例是null。
3) null是Null的实例,类似Java中的null
4) Nil 是case object,定义为case object Nil extends List[Nothing], 代表一个空list,长度为0。由于Scala中的List是协变的,因此无论T是何种类型,Nil都是List[T]的实例。
5) None 是case object,定义为:case object None extends Option[Nothing],代表不存在的值。Option有两个实例。None和Some
6) Unit 是class,定义为:abstract final class Unit extends AnyVal。Unit跟Java中的void相当,当一个方法不返回任何值的时候,那么方法的类型是Unit。Unit唯一的一个实例是().

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:129832次
    • 积分:2818
    • 等级:
    • 排名:第13435名
    • 原创:144篇
    • 转载:9篇
    • 译文:0篇
    • 评论:15条
    博客专栏
    Spark

    文章:16篇

    阅读:30528
    最新评论