2017-06-15 82 views
0

我剛剛開始學習Scala並且正在關注this tutorial。它們實現Tree結構,如下面的代碼所示,用於創建數學公式。半路通過他們引進type關鍵字作爲無需實例請參見`type`類

type Environment = String => Int 

,使所有的變量可以映射到數字。

我的問題是,如何在沒有Tree實例的情況下引用該類型?即我如何將Environment的類型定義爲static


示例代碼:

package com.company 

/** 
    * The tree class which represents a formula 
    */ 
abstract class Tree { 
    /** 
     * The type to map a variable to a value 
     */ 
    type Environment = String => Int 

    /** 
     * Using the given Environment, it evaluates this tree 
     * @param env The environment which maps variables to values 
     * @return The result of the fomula 
     */ 
    def eval(env: Environment): Int = this match { 
     case Sum(lhs, rhs) => lhs.eval(env) + rhs.eval(env) 
     case Variable(v) => env(v) 
     case Constant(c) => c 
    } 
} 

/** 
    * Represents a sum between to values 
    * @param lhs Left hand value 
    * @param rhs Right hand value 
    */ 
case class Sum(lhs: Tree, rhs: Tree) extends Tree 

/** 
    * Represents an unknown and named value or named variable 
    * @param variable The name of the variable 
    */ 
case class Variable(variable: String) extends Tree 

/** 
    * An unnamed constant value 
    * @param value The value of this constant 
    */ 
case class Constant(value: Int) extends Tree 

/** 
    * Base class for this program 
    */ 
object Tree { 
    /** 
     * Entry point of the application 
     * @param args 
     */ 
    def main(args: Array[String]) { 
     //Define a tree: (x + 3) + 2 
     val tree: Tree = Sum(Sum(Variable("x"), Constant(3)), Constant(2)) 
     //Define an environment: x=5 and y=6 
     val env: tree.Environment = {case "x" => 5; case "y" => 6} 
     //  ^Refers to the object tree rather than the class Tree 
     //val env: Tree.Environment = {case "x" => 5; case "y" => 6} 
     //^Results in the error: Error:(55, 27) type Environment is not a member of object com.company.Tree 

     println(tree) //show the tree 
     println(s"x=${env.apply("x")} | y=${env.apply("y")}") //show values of x and y 
     println(tree.eval(env)) //evaluates the tree 
    } 
} 

回答

1

使用#(類型投影)訪問類型成員不參照該實例:

val env: Tree#Environment = {case "x" => 5; case "y" => 6} 

這裏提供了更多的解釋:What does the `#` operator mean in Scala?

PS因爲JVM實際上「忘記」了這種類型(擦除),所以實際上不能讓您的類型成爲靜態成員的完全意義上的「靜態」,因此tree.EnvironmentTree.Environment(令人驚訝)由編譯器處理,而不是在運行時。即使object Tree{ type Environment = ... }意味着你的類型將是單件對象樹的成員(因此樹仍然有參考)

+0

爲什麼''''操作符不能引用'Environment'?因爲'val樹:樹'是可能的,我認爲? – Didii

+0

@Didii它是一個語法的東西。 '.'旨在從某些參考(單身人士)訪問成員。 '#'不需要這樣的。參見[Type Projection](https://www.scala-lang.org/files/archive/spec/2.11/03-types.html) – dk14

+0

@Didii'val Tree:Tree'實際上不會是一個大問題一種語言 - 除非它會傷害可讀性和美觀。原因是'val樹'可能只是「影射」類Tree(就像本地值可能會影響外部範圍的其他值) - 這是Scala中的常見做法(有時很好,有時不會)。 – dk14

1

在Scala的類型,就像一切,可以由「靜態」通過將其置於對象內。

abstract class Tree 
object Tree { 
    type Environment = String => Int 
} 

我說「靜態」,因爲Scala(語言)沒有像其他一些編程語言一樣的靜態概念。