代码之家  ›  专栏  ›  技术社区  ›  Willis Blackburn

Trait,function,还是Scala中继承function的Trait?

  •  8
  • Willis Blackburn  · 技术社区  · 14 年前

    我在Scala中有一个特性,它只有一个方法。调用它Computable,唯一的方法是compute(input:Int):Int。我不知道是否应该这样做

    • 把它作为一个单独的特性,使用一个方法。
    • 只需去掉Computable并使用(Int=>内景)。

    有利于它成为一种特性的一个因素是,我可以有效地添加一些额外的方法。当然,如果它们都是用计算方法实现的,那么我就可以把它们分解成一个单独的对象。

    支持只使用函数类型的一个因素是简单,而且匿名函数的语法比匿名可计算实例的语法更简洁。但是我没有办法区分那些实际上是可计算实例的对象和其他映射Int到Int的函数,但是它们并不打算在与可计算实例相同的上下文中使用。

    其他人如何处理这类问题?这里没有正确或错误的答案;我只是在寻求建议。

    4 回复  |  直到 14 年前
        1
  •  3
  •   Ken Bloom    14 年前

    创建一个从函数类型扩展而来的特性可能会很有用,原因有两个。

    1. 你的函数对象做了一些特殊的和不明显的事情(而且很难输入),你可以在构造函数中参数化一些细微的变化。例如,假设您正在编写一个trait来对XML树执行XPath查询。apply函数将隐藏构造XPath查询机制的多种工作,但仍然值得实现 Function1 接口,以便您可以使用 map flatMap .

    2. Function 如果没有子类化,编译只能在运行时进行,因此每次查询都会重复编译。)

    3. 您想要传递一个加密函数(一种 Function1[String,String] 函数1[String,String] 函数1[String,String] 命名子类/特征 EncryptionFunction ,可以确保仅隐式传递正确子类的函数(声明时不是这样的 Type EncryptionFunction = String => String .)

    我希望这是清楚的。

        2
  •  8
  •   Mirko Stocker    14 年前

    如果您将它作为一种特性,并且仍然希望能够使用轻量级函数语法,那么还可以在需要它们的地方添加隐式转换:

    scala> trait Computable extends (Int => Int)
    defined trait Computable
    
    scala> def computes(c: Computable) = c(5)
    computes: (c: Computable)Int
    
    scala> implicit def toComputable(f: Int => Int) = new Computable { def apply(i: Int) = f(i) }
    toComputable: (f: (Int) => Int)java.lang.Object with Computable
    
    scala> computes( (i: Int) => i * 2 )
    res0: Int = 10
    
        3
  •  1
  •   Edward Dale    14 年前

    听起来你可能想用 structural type . 它们也被称为隐式接口。

    Computable 接受任何有价值的东西 compute(input: Int)

        4
  •  1
  •   Sandor Murakozi    14 年前

    一个选项是定义一个类型(您仍然可以称之为Computable),此时它是Int=>当你需要可计算的东西时就用它。您将获得从Function1继承的所有好处。然后,如果你意识到你需要更多的方法,你可以改变类型的另一个特点。

    首先:

    type Computable = Int => Int
    

    type Computable = ComputableTrait // with its own methods.
    

    它的一个缺点是,您定义的类型实际上不是新类型,而是一种别名。因此,除非将其更改为trait,否则编译器仍将接受其他Int=>Int函数。至少,你(开发人员)可以区分。当您更改为trait(并且差异变得很重要)时,编译器将发现您何时需要可计算但Int=>内景。

    如果希望编译器拒绝其他Int=>Int-s,那么我建议使用trait,但extend Int=>当你需要调用它时,你仍然会有更方便的语法。

    另一个选择可能是拥有一个trait和一个带有接受Int=>的apply方法的伴随对象;Int并由此创建一个可计算的。 然后,创建新的可计算表几乎和编写普通匿名函数一样简单,但仍然需要进行类型检查(隐式转换会使其失效)。此外,您可以毫无问题地混入trait(但是同伴对象的apply不能按原样使用)。