Существует ли способ иметь кортежи с именованными полями в Scala, подобном анонимным классам в C#?

Создайте ярлык и отредактируйте свойство "Start In" ярлыка на каталог, в котором Вы хотите, чтобы cmd.exe запустился.

18
задан Community 23 May 2017 в 12:26
поделиться

3 ответа

object T {
  def main(args: Array[String]) {  
    val e = new { var id = 5; var name = "Prashant" }
    assert(e.id == 5)
  }
}

Хорошо, давайте проясним ситуацию. Это действительно использует отражение в Scala 2.7 и Scala 2.8, потому что тип e в данном случае является структурным типом , который Scala обрабатывает посредством отражения. Вот сгенерированный код во время очистки ( scalac -Xprint: cleanup ):

package <empty> {
  final class T extends java.lang.Object with ScalaObject {
    private <synthetic> <static> var reflMethod$Cache1: java.lang.reflect.Method = null;
    private <synthetic> <static> var reflClass$Cache1: java.lang.Class = null;
    <synthetic> <static> def reflMethod$Method1(x$1: java.lang.Class): java.lang.reflect.Method = {
      if (T.this.reflMethod$Cache1.eq(null).||(T.this.reflClass$Cache1.ne(x$1)))
        {
          T.this.reflMethod$Cache1 = x$1.getMethod("id", Array[java.lang.Class]{});
          T.this.reflClass$Cache1 = x$1;
          ()
        };
      T.this.reflMethod$Cache1
    };
    @remote def $tag(): Int = scala.ScalaObject$class.$tag(T.this);
    def main(args: Array[java.lang.String]): Unit = {
      val e: java.lang.Object = {
        new T$$anon$1()
      };
      scala.this.Predef.assert(scala.Int.unbox({
        var exceptionResult1: java.lang.Object = _;
        try {
          exceptionResult1 = T.reflMethod$Method1(e.getClass()).invoke(e, Array[java.lang.Object]{})
        } catch {
          case ($1$ @ (_: java.lang.reflect.InvocationTargetException)) => {
            exceptionResult1 = throw $1$.getCause()
          }
        };
        exceptionResult1
      }.$asInstanceOf[java.lang.Integer]()).==(5))
    };
    def this(): object T = {
      T.super.this();
      ()
    }
  };
  final class T$$anon$1 extends java.lang.Object {
    private[this] var id: Int = _;
    <accessor> def id(): Int = T$$anon$1.this.id;
    <accessor> def id_=(x$1: Int): Unit = T$$anon$1.this.id = x$1;
    private[this] var name: java.lang.String = _;
    <accessor> def name(): java.lang.String = T$$anon$1.this.name;
    <accessor> def name_=(x$1: java.lang.String): Unit = T$$anon$1.this.name = x$1;
    def this(): T$$anon$1 = {
      T$$anon$1.this.id = 5;
      T$$anon$1.this.name = "Prashant";
      T$$anon$1.super.this();
      ()
    }
  }
}

Некоторое кеширование происходит, но если я чередую id и ] name он уже сделает кеш недействительным. Scala 2.8 также выполняет отражение, а также кэширует, но использует более эффективный метод кэширования, который должен обеспечить лучшую общую производительность. Для справки, вот чистая версия Scala 2.8:

package <empty> {
  final class T extends java.lang.Object with ScalaObject {
    final private <synthetic> <static> var reflParams$Cache1: Array[java.lang.Class] = Array[java.lang.Class]{};
    @volatile
    private <synthetic> <static> var reflPoly$Cache1: scala.runtime.MethodCache = new scala.runtime.EmptyMethodCache();
    <synthetic> <static> def reflMethod$Method1(x$1: java.lang.Class): java.lang.reflect.Method = {
      var method1: java.lang.reflect.Method = T.reflPoly$Cache1.find(x$1);
      if (method1.ne(null))
        return method1
      else
        {
          method1 = x$1.getMethod("id", T.reflParams$Cache1);
          T.reflPoly$Cache1 = T.reflPoly$Cache1.add(x$1, method1);
          return method1
        }
    };
    def main(args: Array[java.lang.String]): Unit = {
      val e: java.lang.Object = {
        new T$$anon$1()
      };
      scala.this.Predef.assert(scala.Int.unbox({
        val qual1: java.lang.Object = e;
        {
          var exceptionResult1: java.lang.Object = _;
          try {
            exceptionResult1 = T.reflMethod$Method1(qual1.getClass()).invoke(qual1, Array[java.lang.Object]{})
          } catch {
            case ($1$ @ (_: java.lang.reflect.InvocationTargetException)) => {
              exceptionResult1 = throw $1$.getCause()
            }
          };
          exceptionResult1
        }.$asInstanceOf[java.lang.Integer]()
      }).==(5))
    };
    def this(): object T = {
      T.reflParams$Cache1 = Array[java.lang.Class]{};
      T.reflPoly$Cache1 = new scala.runtime.EmptyMethodCache();
      T.super.this();
      ()
    }
  };
  final class T$$anon$1 extends java.lang.Object {
    private[this] var id: Int = _;
    <accessor> def id(): Int = T$$anon$1.this.id;
    <accessor> def id_=(x$1: Int): Unit = T$$anon$1.this.id = x$1;
    private[this] var name: java.lang.String = _;
    <accessor> def name(): java.lang.String = T$$anon$1.this.name;
    <accessor> def name_=(x$1: java.lang.String): Unit = T$$anon$1.this.name = x$1;
    def this(): T$$anon$1 = {
      T$$anon$1.super.this();
      T$$anon$1.this.id = 5;
      T$$anon$1.this.name = "Prashant";
      ()
    }
  }
}
19
ответ дан 30 November 2019 в 06:42
поделиться

Scala 2.8 улучшила систему типов до такой степени, что стало возможно иметь статически и неоднородно типизированные массивы и списки, так что предположительно можно было бы сделать то же самое. с картами. Ознакомьтесь с его реализацией в блоге Йеспера Норденберга «Списки типов и неоднородно типизированные массивы» .

1
ответ дан 30 November 2019 в 06:42
поделиться

Вы также можете назвать части кортежа, которым вы назначаете, например:

val (ID, Name) = (5, "Prashant")
assertEquals( 5, ID )

Вы также можете использовать это как:

val (ID, Name, Age) = functionThatReturnsATuple3
println("ID: " + ID + ", age: " + Age)

Когда я впервые прочитал о _x синтаксис Я подумал, что он великолепен, и много использовал его. С тех пор я практически перестал его использовать, так как, когда мне нужно посмотреть на код, который я написал два месяца назад, я должен потратить уйму времени, пытаясь выяснить, какие типы _1 , _2 и др. Есть. Я полагаю, что в ретроспективе очевидно, что id гораздо более читабелен, чем pair._1 .

Это также может использоваться внутри таких функций, как map , фильтр и т. д., например:

val list: List[ (Int, String, Double) ] = ...
list map { case (id, name, time) => ... }
list filter { case (_, name, _) => name == "X" }

Обратите внимание, что в фильтре вы можете использовать _ для элементов, которые вы не собираетесь использовать в теле функции. .

14
ответ дан 30 November 2019 в 06:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: