Java泛型可以根据表达式的返回类型推断出泛型类型参数的类型。请考虑以下事项:
public static <T> T uncheckedCast(Object o) {
return (T)o;
}
我们可以这样调用它:
Map<Baz,Bog> bazbogMap = new HashMap<Baz,Bog>();
String foo = uncheckedCast(bazbogMap);
这将编译但抛出 RuntimeException当它被调用时,因为它会尝试转换 Map到 String但失败了。但重点是 Java 推断出 <T> 的值。基于调用站点的预期结果类型。
我们也可以在 Scala 中使用:
def uncheckedCast[T](o: AnyRef): T = o.asInstanceOf[T]
到目前为止,还不错。
Java 还可以从嵌套定义中推断类型参数并返回它们(即,我们实际上不必像上面那样在使用之前将结果分配给类型;Java 已经知道它是什么了。)
一个简单的类展示了这一点:
import java.util.HashMap;
import java.util.Map;
public class KeysAndValues {
public interface Key<T> {}
public static class StringKey implements Key<String> {}
private final Map<Class<?>, Object> lookup;
public KeysAndValues() {
lookup = new HashMap<Class<?>, Object>();
}
@SuppressWarnings("unchecked")
public <V, K extends Key<V>> V put(Class<K> key, V value) {
return (V) lookup.put(key, value);
}
@SuppressWarnings("unchecked")
public <V, K extends Key<V>> V get(Class<K> key) {
return (V) lookup.get(key);
}
public static void test() {
KeysAndValues kv = new KeysAndValues();
kv.put(StringKey.class, "BAM!"); // returns null
kv.put(StringKey.class, "BOOM!"); // returns "BAM!"
kv.get(StringKey.class); // returns "BOOM!"
}
}
但是,在 Scala 中,此类会导致问题。回复:
scala> val kv = new KeysAndValues
kv: KeysAndValues = KeysAndValues@13c2982e
scala> import KeysAndValues.StringKey
import KeysAndValues.StringKey
scala> kv.put(classOf[StringKey], "BAM!")
res0: java.lang.String = null
scala> kv.put(classOf[StringKey], "BOOM!")
res1: java.lang.String = BAM!
scala> kv.get(classOf[StringKey])
<console>:10: error: inferred type arguments [Nothing,KeysAndValues.StringKey] do not conform to method get's type parameter bounds [V,K <: KeysAndValues.Key[V]]
kv.get(classOf[StringKey])
两次调用 put()为 V 指定一个值允许它们工作的类型参数,但一旦 V需要从 K 的继承中提取参数参数,事情崩溃了。 Java代码没有这样的问题。
让 Scala 不提示的唯一方法是显式定义类型:
kv.get[String, StringKey](classOf[StringKey])
(对于像上面这样的简单和人为的事情,它还可以(违反 DRY),但对于更复杂的事情,比如 Stanford Core NLP API,你必须做这样的事情:
doc.get[java.util.Map[Integer, CorefChain], CorefChainAnnotation](classOf[CorefChainAnnotation])
其中包括手动查找嵌套类型以便您可以添加它们,这非常痛苦。)
问题:
有没有办法让它工作而不必如此冗长地指定类型参数?更重要的是,为什么这是一个问题?当 Scala 不能时,Java 如何能够推断类型参数?
编辑 1:删除了大部分演示 Stanford Core NLP 问题的代码,并将其替换为说明该问题的 Scala/Java 泛型差异的一般示例。
最佳答案
我不能确切地告诉你为什么 Scala 不能推断出 Java 类型参数,但我至少可以告诉你如何在 Java 中声明类型参数以便 Scala 可以 推断它们:
@SuppressWarnings("unchecked")
public <V> V put(Class<? extends Key<V>> key, V value) {
return (V) lookup.put(key, value);
}
@SuppressWarnings("unchecked")
public <V> V get(Class<? extends Key<V>> key) {
return (V) lookup.get(key);
}
我认为这里的关键点是您不需要 K完全类型参数 - 通配类型参数,? extends Key<V>将为您提供相同的功能。然后,这可以在 Scala 中愉快地工作,而无需指定任何类型参数:
scala> kv.put(classOf[StringKey], "BAM!")
res0: String = null
scala> kv.get(classOf[StringKey])
res1: String = BAM!
编辑:
这是我能做的最好的解决方法。它需要更高级的类型和类型转换。不确定我能解释为什么这个编译但另一个版本没有。 ;-)
scala> import KeysAndValues._
import KeysAndValues._
scala> import scala.language.higherKinds
import scala.language.higherKinds
scala> def get[V, K[X] <: Key[X]](kv: KeysAndValues, key: Class[_ <: K[V]]) =
| kv.get[V, K[V]](key.asInstanceOf[Class[K[V]]])
get: [V, K[X] <: KeysAndValues.Key[X]](kv: KeysAndValues, key: Class[_ <: K[V]])V
scala> val kv = new KeysAndValues
kv: KeysAndValues = KeysAndValues@24c63dac
scala> kv.put(classOf[StringKey], "BAM!")
res0: String = null
scala> get(kv, classOf[StringKey])
res1: String = BAM!
关于java - Scala 和 Java 泛型——提取和返回嵌套类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14815751/
我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib
这道题是thisquestion的逆题.给定一个散列,每个键都有一个数组,例如{[:a,:b,:c]=>1,[:a,:b,:d]=>2,[:a,:e]=>3,[:f]=>4,}将其转换为嵌套哈希的最佳方法是什么{:a=>{:b=>{:c=>1,:d=>2},:e=>3,},:f=>4,} 最佳答案 这是一个迭代的解决方案,递归的解决方案留给读者作为练习:defconvert(h={})ret={}h.eachdo|k,v|node=retk[0..-2].each{|x|node[x]||={};node=node[x]}node[
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串
我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
下面例子中的Nested和Child有什么区别?是否只是同一事物的不同语法?classParentclassNested...endendclassChild 最佳答案 不,它们是不同的。嵌套:Computer之外的“Processor”类只能作为Computer::Processor访问。嵌套为内部类(namespace)提供上下文。对于ruby解释器Computer和Computer::Processor只是两个独立的类。classComputerclassProcessor#Tocreateanobjectforthisc
我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的