1. Unified Type System
Scala has a unified type system, enclosed by the type Any at the top of the hierarchy and the type Nothing at the bottom of the hierarchy. All Scala types inherit from Any.

# Using Any, Book extends AnyRef, and x is an Int that extends AnyVal
scala> import scala.collection.mutable.ListBuffer
import scala.collection.mutable.ListBuffer
scala> val list = ListBuffer[Any]()
list: scala.collection.mutable.ListBuffer[Any] = ListBuffer()
scala> val x =
x: Int =
scala> list += x
res11: list.type = ListBuffer()
scala> class Book
defined class Book
scala> list += new Book
res12: list.type = ListBuffer(, Book@4894a95e) # limit a method to only be able to work on Value Types
scala> def test(int: AnyVal) = ()
test: (int: AnyVal)Unit
scala> test()
scala> test(5.12)
scala> test(new Object)
<console>:: error: type mismatch;
found : java.lang.Object
required: AnyVal
test(new Object)
^

2. Type Parameterization
  Classes and traits that take type parameters are called generic; the types they generate are called parameterized type.

# Scala List of Strings
scala> val list: List[String] = List("A","B")

   Note that the Set[T] is a trait, but not a type because it takes a type parameter.

# Scala requires to specify type parameters
scala> def test(s: Set){}
<console>:: error: type Set takes type parameters
def test(s: Set){}
^
# specifying parameter types
scala> def test(s: Set[AnyRef]){}
test: (s: Set[AnyRef])Unit

  In Scala, List, Set and so on also be referred as a type constructors, because they are used to create specific types. You could construct a type by specifying a type parameter.

    (1) Variance
    A declaration like class Set[+A] means that Set is parameterized by a type A. The + is called a variance annotation【型变注释】.
    Variance comes in three flavors: invariant【不变】, covariant【协变】, and contravariant【逆变】. Variance in Scala is defined by using + and - signs in front of type parameters.
      1) Covariant Parameter Types
      Covariant parameter types are designated with a + before the type parameter. A covariant type is useful for read-only containers.

      If S extends T then Class[S] extends Class[T].

# immutable class Getable
scala> class Getable[+T](val data: T)
defined class Getable
# define a method that takes a Getalbe
scala> def get(in: Getable[Any]){println("It's "+in.data)}
get: (in: Getable[Any])Unit
# instance of Getable
scala> val gs = new Getable("String")
gs: Getable[java.lang.String] = Getable@6a6877c1
scala> get(gs)
It's String #passing Double
scala> def getNum(in: Getable[Number]) = in.data.intValue
getNum: (in: Getable[java.lang.Number])Int
scala> def gd = new Getable(new java.lang.Double(3.3))
gd: Getable[java.lang.Double]
scala> getNum(gd)
res17: Int =

      We can make read-only classes covariant.

    2) Contravariant Parameter Types
      Contravariance indicates if S extends T, then class[T] extends Class[S].

# Putable Class
scala> class Putable[-T]{def put(in: T){println("Putting "+in)}}
defined class Putable
# method takes a Putable[String]
scala> def writeOnly(in: Putable[String]){in.put("Hello")}
writeOnly: (in: Putable[String])Unit
# declare an instance of Putable[AnyRef]
scala> val p = new Putable[AnyRef]
p: Putable[AnyRef] = Putable@3a5a8982
scala> writeOnly(p)
Putting Hello

      The inputs to a transformation are contravariant. Calling something that expects at least AnyRef with a String is legal and valid. But the return value can be covariant because we expect to get back a Number, so if we get an Integer, a subclass of Number, we're okay.

# define DS with a contravariant In type and a covariant Out type.
scala> trait DS[-In, +Out]{def apply(i: In): Out}
defined trait DS
# create an instance that will convert Any into an Int
scala> val t1 = new DS[Any, Int]{def apply(i: Any) = i.toString.toInt}
t1: java.lang.Object with DS[Any,Int] = $anon$@4f7620f1
scala> def check(in: DS[String, Any]) = in("333")
check: (in: DS[String,Any])Any
scala> check(t1)
res19: Any =

    3) Invariant Parameter Types

      In Scala, Array[T] is invariant. This means that you can only pass an Array[String] to foo(a: Array[String]).

# define an invariant class
scala> class Holder[T](var data: T)
defined class Holder
scala> def add(in: Holder[Int]){in.data = in.data + }
add: (in: Holder[Int])Unit
scala> val h = new Holder()
h: Holder[Int] = Holder@3d85fdbe
scala> add(h)
scala> h.data
res21: Int =

    Because the add method expects an Int to come out of Holder and puts an Int back into the Holder, the type of the Holder must be invariant.

     Let's put a Double into a Holder[Number]:

scala> val nh = new Holder[Number](33.3d)
nh: Holder[java.lang.Number] = Holder@4e3540c7
scala> def round(in: Holder[Number]){in.data = in.data.intValue}
round: (in: Holder[java.lang.Number])Unit
scala> round(nh)
scala> nh.data
res4: java.lang.Number =

    We put a Number and got back a Number.

# the underlying class
scala> nh.data.getClass
res5: java.lang.Class[_ <: java.lang.Number] = class java.lang.Integer # try to pass a Holder[Double] into round
scala> val dh = new Holder(33.3d)
dh: Holder[Double] = Holder@5a3a5cc5 scala> round(dh)
<console>:: error: type mismatch;
found : Holder[Double]
required: Holder[java.lang.Number]
round(dh)
^

    4) Rules of Variance

    Mutable containers should be invariant. Immutable containers should be covariant. Inputs to transformations should be contravariant, and outputs from transformations should be covariant.
 
 (2) Type Bounds
    1) Upper Type Bounds
    An Upper bound type is restricted to a specific type or one of its derived types. Scala provides the upper bound relation operator (<:). The <: operator signifies that the type to the left of the <: operator must be a subtype or be the same type of the type to the right of the <: operator.

#define an Employee class hierarchy
scala> class Employee(val name: String)
defined class Employee
scala> class Internal(name: String) extends Employee(name)
defined class Internal
scala> class FreeLancer(name: String) extends Employee(name)
defined class FreeLancer
scala> class Customer(name: String)
defined class Customer # define a function that takes a parameter with an upper bound
scala> def employeeName[A <: Employee](emp: A){println(emp.name)}
employeeName: [A <: Employee](emp: A)Unit scala> employeeName(new Internal("Paul"))
Paul
scala> employeeName(new FreeLancer("John"))
John
# the Customer class is not a subtype of Employee.
scala> employeeName(new Customer("Peter"))
<console>:: error: inferred type arguments [Customer] do not conform to method employeeName's type parameter bounds [A <: Employee]
employeeName(new Customer("Peter"))
^

  2) Lower Type Bounds
  A lower bound type is restricted to a specific type or its supertype. The type selected must be equal to or a supertype of the lower bound restriction.

scala> class A{
| type B >: List[Int]
| def something(a: B) = a
| }
defined class A
# instantiate the subtype
scala> val st = new A{ type B = Traversable[Int]}
st: A{type B = Traversable[Int]} = $anon$@57a3687
scala> st.someMethod(Set(,))
res0: st.B = Set(, )

  Even if Set is not a supertype of the List class, it's a subtype of Traversable.
3. Implicit Class
  The String class seems to have grown methods:

scala> "Hello".toList
res0: List[Char] = List(H, e, l, l, o)

  If you have an instance of a particular type, and you need another type, and there's an implicit conversion in scope, Scala will call the implicit method to perform the conversion.

# create a method that calculates the number of days based on a Long containing a millisecond count
scala> def millisToDays(in: Long): Int = (in / (1000L*3600L*)).toInt
millisToDays: (in: Long)Int
scala> millisToDays(5949440999L)
res1: Int =
# try to pass a Date into the method
scala> millisToDays(new Date)
<console>:: error: type mismatch;
found : java.util.Date
required: Long
millisToDays(new Date)
^
# define a method that will automatically be called when we need the conversion
scala> implicit def dateToLong(d: Date) = d.getTime
dateToLong: (d: java.util.Date)Long
scala> millisToDays(new Date)
res5: Int =

  You should be very careful with implicit conversions, and their use should be an explicit design choice. However, we see that sometimes implicit conversions(Int -> Long) are very valuable.

# a method that takes a parameter that must be a Long
scala> def m2[T <: Long](in: T):Int = (in / (1000L * 3600L * 24L)).toInt
m2: [T <: Long](in: T)Int
scala> m2()
<console>:: error: inferred type arguments [Int] do not conform to method m2's type parameter bounds [T <: Long]
m2()
^
scala> m2(33L)
res7: Int =

  What is the scope of implicits? Scala compiler considers an implicit in the current scope if:
  1) The implicit is defined in the current class or in a superclass.
  2) The implicit is defined in a trait or supertrait, or is mixed into the current class or superclass
  3) The implicit is defined on the companion object of the current target class.
  4) The implicit is available on an object that has been imported into the current scope.
  When designing libraries, be careful about defining implicits, and make sure they are in as narrow a scope as is reasonable. When consuming libraries, make sure the implicits defined in the objects are narrow enough and are not going to cause problems such a getting stuff from every Option.
  An implicit class is a class marked with the implicit keyword. The keyword makes the class's primary constructor available for implicit conversions when the class is in scope.

Beginning Scala study note(8) Scala Type System的更多相关文章

  1. Beginning Scala study note(9) Scala and Java Interoperability

    1. Translating Java Classes to Scala Classes Example 1: # a class declaration in Java public class B ...

  2. Beginning Scala study note(6) Scala Collections

    Scala's object-oriented collections support mutable and immutable type hierarchies. Also support fun ...

  3. Beginning Scala study note(3) Object Orientation in Scala

    1. The three principles of OOP are encapsulation(封装性), inheritance(继承性) and polymorphism(多态性). examp ...

  4. Beginning Scala study note(2) Basics of Scala

    1. Variables (1) Three ways to define variables: 1) val refers to define an immutable variable; scal ...

  5. Beginning Scala study note(7) Trait

    A trait provides code reusability in Scala by encapsulating method and state and then offing possibi ...

  6. Beginning Scala study note(4) Functional Programming in Scala

    1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...

  7. Beginning Scala study note(1) Geting Started with Scala

    1. Scala is a contraction of "scalable" and "language". It's a fusion of objecte ...

  8. Beginning Scala study note(5) Pattern Matching

    The basic functional cornerstones of Scala: immutable data types, passing of functions as parameters ...

  9. So the type system doesn’t feel so static.

    object wb{ def main(args:Array[String]){ println("Happy everyday!DATA-CENTER!") println(ne ...

随机推荐

  1. Apache Shiro 学习记录4

    今天看了教程的第三章...是关于授权的......和以前一样.....自己也研究了下....我觉得看那篇教程怎么说呢.....总体上是为数不多的精品教程了吧....但是有些地方确实是讲的太少了.... ...

  2. Alpha阶段项目总结

    1.我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件是一款面向高校学生的简单快速的云笔记,不仅具有笔记的添加.修改.查看和删除功能,还有笔记公开功能,用户 ...

  3. Timequest静态时序分析(STA)基础

    Setup Slack Hold Slack Recovery&Removal Recovery: The minimum time an asynchronous signal must b ...

  4. mybatis逆向工程生成JavaBean、dao、mapper generatorSqlmapCustom

    import java.io.File; import java.util.ArrayList; import java.util.List; import org.mybatis.generator ...

  5. CentOS 7 环境配置

    1. 代理设置 http://blog.csdn.net/fwj380891124/article/details/42168683 2. xfce 桌面安装 http://blog.csdn.net ...

  6. excel使用技巧

    1,如何得到开口向下的大括号 1,插入左右方向的大括号. 2,点击绘制的大括号,旋转出现绿点,旋转90度,即可. 问题2:Excel如何截图 1,选中截图内容,选择复制->复制为图片->( ...

  7. WPF剪切板问题-OpenClipboard HRESULT:0x800401D0 (CLIPBRD_E_CANT_OPEN))

    WPF剪切板问题-OpenClipboard HRESULT:0x800401D0 (CLIPBRD_E_CANT_OPEN))       最近碰到一个问题,需要弄个小工具来解决.刚好接触到WPF, ...

  8. Linux+PHP+MySql网站迁移配置

    LINUX下MYSQL数据库默认数据库文件位置: 数据库文件默认在:cd /usr/share/mysql 配置文件默认在:/etc/my.cnf ———————————– 数据库目录:/var/li ...

  9. 【翻译】Fluent NHibernate介绍和入门指南

    英文原文地址:https://github.com/jagregory/fluent-nhibernate/wiki/Getting-started 翻译原文地址:http://www.cnblogs ...

  10. js:使用js过程中遇到的一个小问题

    在一个作业中使用了js,函数A调用函数B.当A和B中均含有变量i的时候,相关操作结果可能会出错. 将B中的i替换为j(j不存在于A中)后,结果正确. 目前考虑原因是两个变量i有相关性(或者说实际上就是 ...