Groovy:从方法内部动态确定预期的返回类型?

Groovy:从方法内部动态确定预期的返回类型?,groovy,overloading,return-type,Groovy,Overloading,Return Type,在Groovy中,是否可以在方法中确定预期结果 实际上,这意味着按返回类型重载 动机:DB查询方法,可能返回也可能不返回精确的1或0..*结果。 如果为1,则会抛出;如果为0..*,则只返回一个集合 因此,我只希望有一个查询(…),在这些情况下,它将返回List或Foo: List<Foo> foos = query("FROM Foo"); Foo foo = query("FROM Foo f WHERE f.id = 1"); 附加问题:一些语言支持这一点吗?G

在Groovy中,是否可以在方法中确定预期结果

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

动机:DB查询方法,可能返回也可能不返回精确的1或0..*结果。 如果为1,则会抛出;如果为0..*,则只返回一个集合

因此,我只希望有一个
查询(…)
,在这些情况下,它将返回
List
Foo

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

附加问题:一些语言支持这一点吗?

Groovy允许您使用
def
关键字声明不带类型的变量。因此,您可以编写:

def foo = query("FROM Foo"); // "foo" will contain a List<Foo>
也就是说,这取决于你如何使它以正确的方式工作。为了方便起见,我建议您始终返回一个集合,其中可能只包含一个项目


根据经验,如果你期望不同的回报类型,你可能需要两种不同的行为来处理它们,所以最好有两种方法

Groovy允许您使用
def
关键字声明不带类型的变量。因此,您可以编写:

def foo = query("FROM Foo"); // "foo" will contain a List<Foo>
也就是说,这取决于你如何使它以正确的方式工作。为了方便起见,我建议您始终返回一个集合,其中可能只包含一个项目


根据经验,如果你期望不同的回报类型,你可能需要两种不同的行为来处理它们,所以最好有两种方法

我不确定这是否正是您想要的,但看看它是否有帮助:

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>
类T{}
def func(t){
列表a=[new T(),new T()]
tb=新的T()
如果(t>1)返回(列表)a
如果(t==1)返回(t)b
}
assert func(1)instanceof T
assert func(2)instanceof List

我不确定这是否正是您想要的,但看看它是否有帮助:

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>
类T{}
def func(t){
列表a=[new T(),new T()]
tb=新的T()
如果(t>1)返回(列表)a
如果(t==1)返回(t)b
}
assert func(1)instanceof T
assert func(2)instanceof List

方法返回重载意味着使用不同的返回类型编写相同的方法。JVM允许它,尽管Java不允许。Groovy可以,但它无法正确解析将调用哪个方法,如C++、Haskell、Perl和艾达。 至于您想要什么,是的,只需返回方法应该返回的内容,并将
def
作为方法的返回类型。如果不需要
def
返回类型,则需要
List
Foo
的超类型(当您使用
CompileStatic/TypeChecked
时,编译器可以推断出这两个超类型)

对于调用者,旧的
实例(或开关盒)执行以下操作:

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

更新

编译器将推断一个公共超类型作为返回类型。如果它没有你尝试使用的方法,你必须根据它来“分叉”。如果您不喜欢
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
的公共超类型:
对象

方法返回重载意味着使用不同的返回类型编写相同的方法。JVM允许它,尽管Java不允许。Groovy可以,但它无法正确解析将调用哪个方法,如C++、Haskell、Perl和艾达。 至于您想要什么,是的,只需返回方法应该返回的内容,并将
def
作为方法的返回类型。如果不需要
def
返回类型,则需要
List
Foo
的超类型(当您使用
CompileStatic/TypeChecked
时,编译器可以推断出这两个超类型)

对于调用者,旧的
实例(或开关盒)执行以下操作:

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

更新

编译器将推断一个公共超类型作为返回类型。如果它没有你尝试使用的方法,你必须根据它来“分叉”。如果您不喜欢
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

的通用超类型,是的,但我不喜欢使用“…多”或“…单”之类的方法来区分方法。因此问题就来了。@OndraŽižka如果问题是“groovy能否在运行时存储不同的变量对象?”答案是肯定的,使用
def
关键字。如果要检查从方法返回的类型,也可以这样做(请参见[)。这是否回答了您的问题?问题是我是否可以在方法中确定它。更改标题以强调这一方面。抱歉,可能只是我,但我看不到您希望做什么。首先,哪一个是“方法”你在说什么?为什么你想在其中声明方法的返回类型?你能编辑你的问题,添加一个你希望能够编写的代码的例子吗?是的,但我不喜欢用“…多”或“…单”之类的东西来区分方法。因此问题就来了。@OndraŽIžka,如果问题是这样的话“groovy能否在运行时将不同的对象存储在变量中?”答案是肯定的,使用
def
关键字。如果要检查从方法返回的类型,也可以这样做(请参见[)。这是否回答了您的问题?问题是