0

在 Groovy 中是否可以在方法中确定预期结果是什么?

实际上,这意味着按返回类型重载。

动机:数据库查询方法可能会或可能不会准确返回 1 或 0..* 结果。如果为 1,那么它会抛出;如果为 0..*,它只会返回一个集合。

所以我想只有一个query(...)会返回List<Foo>Foo在这些情况下:

List<Foo> foos = query("FROM Foo");
Foo foo        = query("FROM Foo f WHERE f.id = 1");

query伪代码将是:

Object query( String q ){
    if( Collection.class.isAssignableFrom( GET_CURRENT_METHODS_RETURN_TYPE ) ){
         return new LinkedList(){ ... }
    }
    if( Foo.class == GET_CURRENT_METHODS_RETURN_TYPE ) ){
         return new Foo(); // TODO
    }
}

额外的问题:某些语言是否支持这一点?

4

3 回答 3

2

我不确定这是否正是您正在寻找的,但看看它是否有帮助:

class T {}

def func(t) {
    List <T> a = [new T(), new T()]
    T b = new T()

    if (t > 1) return (List <T>)a
    if (t == 1) return (T)b
}

assert func(1) instanceof T
assert func(2) instanceof List<T>
于 2013-06-04T17:24:12.393 回答
2

方法返回重载意味着编写具有不同返回类型的相同方法。JVM 允许这样做,尽管 Java 不允许。Groovy 可以,但它无法正确解析将调用哪个方法。有一些语言支持这一点,如 C++、Haskell、Perl 和 Ada。

至于你想要什么,是的,只需返回方法应该返回的任何内容并def作为方法的返回类型。如果您不想要返回类型,则需要anddef的超类型(编译器可以在使用 时推断出)。List<Foo>FooCompileStatic/TypeChecked

对于调用者,旧的instanceof(或 switch-case)可以解决问题:

class Foo{}

class Database {
  def query(String query) {
    if (query.contains(".id")) { // here you will make a call to database
      new Foo()
    } else {
      []
    }
  }
}

db = new Database()
assert db.query("from Foo f where f.id = 3") instanceof Foo
assert db.query("from Foo f") instanceof List

更新

编译器将推断一个常见的超类型作为返回类型。如果它不是具有您尝试使用的方法的东西,您将不得不根据它“分叉”。如果您不喜欢s ,那么有一个扩展可以进行模式匹配:if

import groovy.transform.CompileStatic

@CompileStatic
class Cases {
  static main(args) {
    def returned = new Cases().query 10
    //returned[1] // doesn't work: returned is of the common type 
                  // OBJECT, which has no getAt method

    returned.case {
      when String then { println it } // will print "a string"
      when List then { List l -> println l.head() } // compiles fine, won't be executed
    }
  }

  def query(obj) {
    if (obj == 10) {
      "a string"
    } else {
      [1, 2, 3]
    }
  }
}

这是 Groovy 推理的亮点:

import groovy.transform.CompileStatic

@CompileStatic
class Cases {
  static main(args) {
    assert new Cases().foo().baz == "w00t"
  }

  def foo() {
    new Foo(baz: "w00t")
  }
}

class Foo { String baz }

您编写def foo()并且它知道该方法将返回一个Foo对象。美丽的。


如果可能的实现中有一个共同的超类,它将被选中:

import groovy.transform.CompileStatic

@CompileStatic
class Cases {
  static main(args) {
    def bat = new Cases().animal 1
    assert bat.name == "bat"
    assert bat.favoriteBloodType == "A+" // Won't compile with error 
                                         // "No such property: favoriteBloodType
                                         // for class: Animal"
  }

  def animal(int animalCode) {
    if (animalCode == 1) {
      new Bat(name: "bat", favoriteBloodType: "A+")
    } else {
      new Chicken(name: "chicken", weight: 3.4)
    }
  }
}

abstract class Animal {
  String name
}

class Bat extends Animal {
  String favoriteBloodType
}

class Chicken extends Animal {
  BigDecimal weight
}

Foo在您的情况下,编译器将推断两者的共同超类型List: Object

于 2013-06-08T19:28:07.797 回答
1

Groovy 允许您使用def关键字声明没有类型的变量。所以你可以写:

def foo = query("FROM Foo"); // "foo" will contain a List<Foo>

或者:

def foo = query("FROM Foo f WHERE f.id = 1"); // "foo" will contain a Foo object

也就是说,由您决定是否以正确的方式工作。为此,我建议您始终返回一个集合,该集合可能只包含一个项目。

根据经验,如果您期望不同的返回类型,您可能需要两种不同的行为来处理它们,所以有两种方法就可以了。

于 2013-06-04T11:15:13.910 回答