【问题标题】:Scala Generic Array ElementsScala 通用数组元素
【发布时间】:2017-09-29 23:06:47
【问题描述】:

我正在尝试编写一个函数来计算类型 T 的元素数组中通过 T=>Boolean 类型测试的元素数。

到目前为止我所拥有的是:

     def countPass[T](elem: Array[T]) = {
        var count = 0
        for(x <- elem) 
            x match { 
                case x: T => count += 1
            }
        count
    }

    //TEST
    println(countPass[Boolean](Array(true, 52, "test")))

我遇到了几个错误,第一个是:

combinators.scala:45: warning: abstract type pattern T is unchecked since
it is eliminated by erasure
                        case x: T => count += 1
                                ^

下一个错误是:

combinators.scala:54: error: type mismatch;
 found   : Int(52)
 required: Boolean
    println(countPass[Boolean](Array(true, 52, "test")))
                                           ^
combinators.scala:54: error: type mismatch;
 found   : String("test")
 required: Boolean
    println(countPass[Boolean](Array(true, 52, "test")))
                                               ^

我不确定第一个错误发生了什么,但是对于第二个错误,它会在任何时候抛出异常,它不是布尔值。我不希望这种情况发生,因为我只是在计算数组中 T 类型元素的数量。

问题:我应该如何重构我的代码来修复这两个错误?

【问题讨论】:

    标签: arrays scala generics


    【解决方案1】:

    诀窍是使用ClassTag。完成您的请求的更好方法如下:

    import scala.reflect.ClassTag
    
    object Main extends App {
    
      val array: Array[Any] = Array("string1", "string2", "string3", true, false, 13)
    
      def countPass[Other: ClassTag](array: Array[Any]): Int = {
        array.collect { case x: Other => x }.length
      }
    
      println(s"countPass String = ${countPass[String](array)}")
      println(s"countPass Boolean = ${countPass[Boolean](array)}")
      println(s"countPass Int = ${countPass[Int](array)}")
    }
    

    您可以阅读this 以了解有关ClassTagTypeTag 的更多信息

    【讨论】:

    • 这与我最初拥有的和想要完成的目标相去甚远。但是,您的解决方案确实让我意识到我应该在数组参数中使用“任何”。但我仍然遇到第一个错误的问题
    • 由于你的数组包含不同的类型,你的数组的类型必须支持所有的类型。因此,您应该定义一个Array[Any]
    • 确保导入 import scala.reflect.ClassTag。此外,您可以阅读以下内容:medium.com/@sinisalouc/…
    【解决方案2】:

    所以我找到了一种可行的方法,但不是我想要的。

         def countPass[T](elem: Array[T]) = {
            var count = 0
            for(x <- elem) 
                x match { 
                    case _: Boolean => count += 1
                    case _ => None
                }
            count
        }
    
        //TEST
        println(countPass[Any](Array(true, 5, "test", false, false)))
    

    问题是我需要将 Any 传递到数组中,因为那里有不同的类型。此外,我需要稍微更改一下我的案例并添加默认案例。

    这很好用,但我想要更像这样的东西。由于上面指定的相同错误,这不起作用

        def countPass[T](elem: Array[Any]) = {
            var count = 0
            for(x <- elem) 
                x match { 
                    case _: T => count += 1   //Here is the error
                    case _ => None
                }
            count
        }
    
        //TEST
        println(countPass[Boolean](Array(true, 5, "test", false, false)))
    

    由于某种原因,我不能做 _: T 或者我得到这个错误:

    combinators.scala:44: warning: abstract type pattern T is unchecked since 
    it is eliminated by erasure
                    case _: T => count += 1
    

    【讨论】:

    • 要匹配_: T(正确),你需要一个ClassTag[T],正如fcat的回答所说。
    【解决方案3】:

    可以直接使用方法count

    def countPass[T: ClassTag](elem: Array[Any]): Int = elem.count{
        case _ : T => true
        case _ => false
    }
    

    【讨论】:

    • 这不符合 OP 的要求,这是一个 countPass,它计算泛型类型 T 的元素,而不是一个固定的布尔值。如果你用 T 替换你的布尔值,你会得到 OP 的错误。
    • 你是对的,我误解了这个问题......我已经修复了解决方案
    猜你喜欢
    • 1970-01-01
    • 2021-07-05
    • 2022-01-26
    • 2019-07-12
    • 2020-03-06
    • 2012-01-08
    • 1970-01-01
    • 2016-09-19
    • 2013-05-31
    相关资源
    最近更新 更多