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
}
}
奖金问题:某些语言是否支持此内容?
答案 0 :(得分: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>
答案 1 :(得分:2)
方法返回重载意味着使用不同的返回类型编写相同的方法。 JVM允许它,尽管Java没有。 Groovy会这样做,但它无法正确解析将调用哪个方法。 There are some languages which support this,如C ++,Haskell,Perl和Ada。
至于你想要什么,是的,只需返回方法应返回的内容,并将def
作为方法的返回类型。如果您不想要def
返回类型,则需要List<Foo>
和Foo
的超类型(当您使用CompileStatic/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
<强>更新强>:
编译器会将常见的超类型推断为返回类型。如果它不是你想要使用的方法的东西,你将不得不根据它“分叉”。 an extension可以进行模式匹配,如果你不进入if
s:
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
。
答案 2 :(得分: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
那就是说,由你决定让它以正确的方式运作。为了做到这一点,我建议你总是返回一个集合,它可能只包含一个项目。
根据经验,如果你期望不同的返回类型,你可能需要两种不同的行为来处理它们,所以有两种方法都没问题。