Spec2.8Chap12b

※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

12.3 標準的な参照クラス (Standard Reference Classes)

This section presents some standard Scala reference classes which are treated in a special way in Scala compiler - either Scala provides syntactic sugar for them, or the Scala compiler generates special code for their operations . Other classes in the standard Scala library are documented in the Scala library documentation by HTML pages .

この節では、Scala コンパイラ中で特別な方法で扱われる、 いくつかの標準的な Scala 参照クラスを紹介します。 Scala はそれらのために糖衣構文を提供するか、 あるいは、Scala コンパイラは操作ための特別なコードを生成します。 標準 Scala ライブラリ中の他のクラスは、Scala ライブラリドキュメント中に HTML ページの形で文書化されています。



12.3.1 クラス String (Class String)

Scala's String class is usually derived from the standard String class of the underlying host system (and may be identified with it). For Scala clients the class is taken to support in each case a method

Scala の文字列クラスは通常、ホストシステムの標準的な String クラスから派生されます(それと同一視されているかもしれません)。 Scala クライアントに対して、クラスはそれぞれの場合に応じて、 次のメソッドをサポートするとされます。

   def + (that: Any): String

which concatenates its left operand with the textual representation of its right operand .

これは、その左オペランドと右オペランドのテキスト表現を連結します。



12.3.2 タプルクラス (The Tuple Classes)

Scala defines tuple classes Tuplen for n = 2,..., 9. These are defined as follows .

Scala は、n = 2,...,9 に対して、タプルクラス Tuplen を定義しています。 それらは次のように定義されています。

   package scala
   case class Tuplen[+a_1,..., +a_n](_1: a_1,..., _n : a_n) {
     def toString = "(" ++ _1 ++ "," ++ ... ++ "," ++ _n ++ ")"
   }

The implicitly imported predef object (§12.5) defines the names Pair as an alias of Tuple2 and Triple as an alias for Tuple3 .

暗黙のうちにインポートされた predef(事前定義済み)オブジェクト (§12.5)は、 Pair という名前の Tuple2 のエイリアスと、 Tripleという名前の Tuple3 のエイリアスを定義しています。



12.3.3 関数クラス (The Function Classes)

Scala defines function classes Functionn for n = 1,..., 9. These are defined as follows .

Scala は、n = 1,...,9 に対して、関数クラス Functionn を定義しています。 それらは次のように定義されています。

   package scala
   trait Functionn[-a_1,..., -a_n , +b] {
     def apply(x_1: a_1,..., x_n : a_n): b
     def toString = "<function>"
   }

A subclass of Function1 represents partial functions, which are undefined on some points in their domain . In addition to the apply method of functions, partial functions also have a isDefined method, which tells whether the function is defined at the given argument:

Function1 のサブクラスは部分関数を表し、 そのドメインのいくつかの点で未定義です。 関数の apply メソッドに加えて、 部分関数も isDefined メソッドを持っており、それは、 与えられた引数で関数が定義されているかどうかを答えます。:

   class PartialFunction[-A, +B] extends Function1[A, B] {
     def isDefinedAt(x: A): Boolean
   }

The implicitly imported predef object (§12.5) defines the name Function as an alias of Function1 .

暗黙のうちにインポートされる predefオブジェクト (§12.5)は、 名前 Function を Function1 のエイリアスと定義しています。



12.3.4 クラス Array (Class Array)

ジェネリックな配列クラスは、次のように与えられています。

   final   class Array[A](len: Int) extends Seq[A] {
     def   length: Int = len
     def   apply(i: Int): A = ...
     def   update(i: Int, x: A): Unit = ...
     def   elements: Iterator[A] = ...
     def   subArray(from: Int, end: Int): Array[A] = ...
     def   filter(p: A => Boolean): Array[A] = ...
     def   map[B](f: A => B): Array[B] = ...
     def   flatMap[B](f: A => Array[B]): Array[B] = ...
   }

If T is not a type parameter or abstract type, the type Array[T] is represented as the native array type []T in the underlying host system . In that case length returns the length of the array, apply means subscripting, and update means element update .

もし T が型パラメータあるいは抽象型でないなら、型 Array[T] は ホストシステム中のネイティブな配列型 []T として表現されます。 そのような場合、length は配列の長さを返し、apply は添え字指定を意味し、 update は要素の更新を意味します。

Because of the syntactic sugar for apply and update operations (§6.26), we have the following correspondences between Scala and Java/C# code for operations on an array xs:

apply と update 操作 (§6.26) の糖衣構文のおかげで、配列 xs の操作について、 Scala と Java/C# のコード間に次の対応があります。:

   Scala               Java/C#
   xs.length           xs.length
   xs(i)               xs[i]
   xs(i) = e           xs[i] = e

Arrays also implement the sequence trait scala.Seq by defining an elements method which returns all elements of the array in an Iterator .

配列は、イテレータ中の配列のすべての要素を返す elements メソッドを定義することで、シーケンストレイト scala.Seq も実装しています。

Because of the tension between parametrized types in Scala and the ad-hoc implementation of arrays in the host-languages, some subtle points need to be taken into account when dealing with arrays . These are explained in the following .

Scala におけるパラメータ化された型と、 ホスト言語における配列のアドホックな実装間の緊張関係のため、 配列を取り扱うとき、いくつかの微妙な点を考慮する必要があります。 それらを次に説明します。

First, unlike arrays in Java or C#, arrays in Scala are not co-variant; That is, S <: T does not imply Array[S] <: Array[T] in Scala . However, it is possible to cast an array of S to an array of T if such a cast is permitted in the host environment .

For instance Array[String] does not conform to Array[Object], even though String conforms to Object . However, it is possible to cast an expression of type Array[String] to Array[Object], and this cast will succeed without raising a ClassCastException .

最初に、Java あるいは C# 中の配列と異なり、Scala 中の配列は共変 ではありません 。;すなわち、Scalaでは、 S <: T が Array[S] <: Array[T] を意味しません。 しかし、S の配列をキャストして T の配列にすることは、 もしそのようなキャストがホスト環境で許されるなら、可能です。

たとえば、String は Objectに適合しますが、インスタンス Array[String] は Array[Object] に適合しません。 しかし、型 Array[String] の式を型 Array[Object] へキャストすることは可能であり、このキャストは ClassCastException を引き起こすことなく成功します。 例:

   val xs = new Array[String](2)
   // val ys: Array[Object] = xs   // **** error: 非互換な型
   val ys: Array[Object] = xs.asInstanceOf[Array[Object]] // OK

Second, for polymorphic arrays, that have a type parameter or abstract type T as their element type, a representation different from []T might be used. However, it is guaranteed that isInstanceOf and asInstanceOf still work as if the array used the standard representation of monomorphic arrays:

第二に、その要素型として型パラメータあるいは抽象型 T を持つ 多相的配列 に対して、[]T と異なる表現が使われることがあります。 しかし、isInstanceOf と asInstanceOf があたかも配列が単相的配列の標準的な表現を使うかのように、 それでも動作することは保証されています。:

   val ss = new Array[String](2)
   
   def f[T](xs: Array[T]): Array[String] =
     if (xs.isInstanceOf[Array[String]]) xs.asInstanceOf[Array[String])
     else throw new Error("not an instance")
   
   f(ss)                                           // ss を返す

The representation chosen for polymorphic arrays also guarantees that polymorphic array creations work as expected . An example is the following implementation of method mkArray, which creates an array of an arbitrary type T , given a sequence of T's which defines its elements .

多相的配列用に選ばれた表現は、 多相的配列の生成が期待どおり動作することも保証しています。 次の例はメソッド mkArray の実装で、その要素を定義する T のシーケンスを与えられ、任意の型 T の配列を生成します。

   def mkArray[T](elems: Seq[T]): Array[T] = {
     val result = new Array[T](elems.length)
     var i = 0
     for (elem <- elems) {
       result(i) = elem
       i += 1
     }
   }

Note that under Java's erasure model of arrays the method above would not work as expected - in fact it would always return an array of Object .

Java の配列の型消去モデルの下では、上のメソッドが期待通りには動作しない

  • 実際、それは常に Object の配列を返す --- ことに注意してください。

Third, in a Java environment there is a method System.arraycopy which takes two objects as parameters together with start indices and a length argument, and copies elements from one object to the other, provided the objects are arrays of compatible element types . System.arraycopy will not work for Scala's polymorphic arrays because of their different representation . One should instead use method Array.copy which is defined in the companion object of class Array . This companion object also defines various constructor methods for arrays, as well as the extractor method unapplySeq (§8.1.8) which enables pattern matching over arrays .

第三に、Java 環境ではメソッド System.arraycopy があります。それは、 2 つのオブジェクトをパラメータにとると共に、開始インデックスと長さの引数を もち、オブジェクトは互換の要素型からなる配列であるとして、 1 つのオブジェクトから他方へ要素をコピーします (訳注:arraycopy(Object src, int srcPos, Object dest, int destPos, int length) )。 System.arraycopy は、Scala の多相的配列に対しては機能しません。 なぜなら、それらの表現が異なるからです。 その代わりに Array.copy を使うべきです。 それはクラス Array のコンパニオンオブジェクト中で定義されています。 このコンパニオンオブジェクトも、 配列上のパターンマッチングを可能にする抽出子メソッド unapplySeq (§8.1.8)と同様、 配列のために種々のコンストラクタメソッドを定義しています。

   package scala
   object Array {
     /** copies array elements from 'src' to 'dest'. */
     /** 'src' から 'dest'へ配列要素をコピー */
     def copy(src: AnyRef, srcPos: Int,
              dest: AnyRef, destPos: Int, length: Int): Unit = ...
   
       /** Concatenate all argument arrays into a single array. */
       /**  1 つの配列へ、すべての引数配列を連結 */
       def concat[T](xs: Array[T]*): Array[T] = ...
   
       /** Create a an array of successive integers. */
       /** 連続した整数からなる配列を生成 */
       def range(start: Int, end: Int): Array[Int] = ...
   
       /** Create an array with given elements. */
       /** 与えられた要素の配列を生成 */
       def apply[A <: AnyRef](xs: A*): Array[A] = ...
   
       /**   Analogous   to above. */
       def   apply(xs: Boolean*): Array[Boolean]   =   ...
       def   apply(xs: Byte*)   : Array[Byte]      =   ...
       def   apply(xs: Short*)  : Array[Short]     =   ...
       def   apply(xs: Char*)   : Array[Char]      =   ...
       def   apply(xs: Int*)    : Array[Int]       =   ...
       def   apply(xs: Long*)   : Array[Long]      =   ...
       def   apply(xs: Float*)  : Array[Float]     =   ...
       def   apply(xs: Double*) : Array[Double]    =   ...
       def   apply(xs: Unit*)   : Array[Unit]      =   ...
   
       /** Create an array containing several copies of an element. */
       /** 要素の複数のコピーを含む配列の生成 */ 
       def make[A](n: Int, elem: A): Array[A] = {
   
       /** Enables pattern matching over arrays */
       /** 配列上のパターンマッチングを可能とする */
       def unapplySeq[A](x: Array[A]): Option[Seq[A]] = Some(x)
   }


Example 12.3.1 次のメソッドは、与えられた引数配列を複写し、 オリジナルと複写したものからなる、ペアを返します:

   def duplicate[T](xs: Array[T]) = {
     val ys = new Array[T](xs.length)
     Array.copy(xs, 0, ys, 0, xs.length)
     (xs, ys)
   }



12.4 クラス Node (Class Node)

   package scala.xml
   
   trait Node {
   
     /** the label of this node */
     /** このノードのラベル */
     def label: String
 
     /** attribute axis */
     /** axis 属性 */
 
     def attribute: Map[String, String]
 
     /** child axis (all children of this node) */
     /** 子 axis (このノードの全ての子) */
     def child: Seq[Node]
 
     /** descendant axis (all descendants of this node) */
     /** 子孫 axis (このノードの全ての子孫) */
     def descendant: Seq[Node] = child.toList.flatMap {
       x => x::x.descendant.asInstanceOf[List[Node]]
     }
   
     /** descendant axis (all descendants of this node) */
     /** 子孫 axis (このノードの全ての子孫) */
     def descendant_or_self: Seq[Node] = this::child.toList.flatMap {
       x => x::x.descendant.asInstanceOf[List[Node]]
     }
   
     override def equals(x: Any): Boolean = x match {
       case that:Node =>
         that.label == this.label &&
           that.attribute.sameElements(this.attribute) &&
             that.child.sameElements(this.child)
       case _ => false
     }
 
     /** XPath style projection function. Returns all children of this node
      * that are labeled with 'that'. The document order is preserved.
      */
     /** XPath スタイルの射影関(projection function)数。'that'と印された、
      *  このノードの全ての子を返す。ドキュメントの順番は維持される。
      */
        def \(that: Symbol): NodeSeq = {
          new NodeSeq({
            that.name match {
              case "_" => child.toList
              case _ =>
                var res:List[Node] = Nil
                for (x <- child.elements if x.label == that.name) {
                  res = x::res
                }
                res.reverse
            }
          })
        }
   
     /** XPath style projection function. Returns all nodes labeled with the
      * name 'that' from the 'descendant_or_self' axis. 
      * Document order is preserved.
      */
     /** XPath スタイルの射影関数。'descendat_or_self'(子孫または自身) axis 
      * から、'that'と印されたこのノードの全ての子を返す。
      * ドキュメントの順番は維持される。
      */
      def \\(that: Symbol): NodeSeq = {
        new NodeSeq(
          that.name match {
           case "_" => this.descendant_or_self
           case _ => this.descendant_or_self.asInstanceOf[List[Node]].
           filter(x => x.label == that.name)
         })
     }
   
     /** hashcode for this XML node */
     /** この XML ノードに対する ハッシュコード */
     override def hashCode =
       Utility.hashCode(label, attribute.toList.hashCode, child)
     /** string representation of this node */
     /** このノードの文字列表現 */
     override def toString = Utility.toXML(this)
   
   }



12.5 事前定義済みオブジェクト (The Predef Object)

The predef object defines standard functions and type aliases for Scala programs . It is always implicitly imported, so that all its defined members are available without qualification . Its definition for the JVM environment conforms to the following signature:

事前定義済みオブジェクトは Scala プログラムの標準関数と型エイリアスを定義します。 これは常に暗黙のうちにインポートされるので、 その定義されたすべてのメンバーは修飾なしで利用可能です。 JVM 環境での定義は、次のシグニチャに一致します:

   package scala
   object Predef {
   
     // classOf -------------------------------------------------------
   
     /** Returns the runtime representation of a class type. */
     /** クラス型の実行時表現を返す */
   
     def classOf[T]: Class[T] = null
      // this is a dummy, classOf is handled by compiler.
      // これはダミー。 classOf はコンパイラによって処理される。
     // 標準の型エイリアス -------------------------------------------
   
     type   byte      =   scala.Byte
     type   short     =   scala.Short
     type   char      =   scala.Char
     type   int       =   scala.Int
     type   long      =   scala.Long
     type   float     =   scala.Float
     type   double    =   scala.Double
     type   boolean   =   scala.Boolean
     type   unit      =   scala.Unit
   
     type String          = java.lang.String
     type Class[T]        = java.lang.Class[T]
     type Runnable        = java.lang.Runnable
   
     type Throwable = java.lang.Throwable
     type Exception = java.lang.Exception
     type Error     = java.lang.Error
   
     type RuntimeException = java.lang.RuntimeException
     type NullPointerException = java.lang.NullPointerException
     type ClassCastException = java.lang.ClassCastException
     type IndexOutOfBoundsException = java.lang.IndexOutOfBoundsException
     type ArrayIndexOutOfBoundsException =
          java.lang.ArrayIndexOutOfBoundsException
     type StringIndexOutOfBoundsException =
          java.lang.StringIndexOutOfBoundsException
     type UnsupportedOperationException =
            java.lang.UnsupportedOperationException
     type IllegalArgumentException = java.lang.IllegalArgumentException
     type NoSuchElementException = java.util.NoSuchElementException
     type NumberFormatException = java.lang.NumberFormatException
   
     // その他 -----------------------------------------------------
   
     type Function[-A, +B] = Function1[A, B]
   
     type Map[A, B] = collection.immutable.Map[A, B]
     type Set[A] = collection.immutable.Set[A]
   
     val Map = collection.immutable.Map
     val Set = collection.immutable.Set
   
     // エラーとアサーション--------------------------------------------
   
     def error(message: String): Nothing = throw new Error(message)
   
     def exit: Nothing = exit(0)
   
     def exit(status: Int): Nothing = {
       java.lang.System.exit(status)
       throw new Throwable()
     }
   
     def assert(assertion: Boolean) {
       if (!assertion)
         throw new java.lang.AssertionError("assertion failed")
     }
   
     def assert(assertion: Boolean, message: Any) {
       if (!assertion)
         throw new java.lang.AssertionError("assertion failed: " + message)
     }
   
     def assume(assumption: Boolean) {
       if (!assumption)
         throw new IllegalArgumentException("assumption failed")
     }
    
     def assume(assumption: Boolean, message: Any) {
       if (!assumption)
         throw new IllegalArgumentException(message.toString)
     }
   
       // tupling ---------------------------------------------------------
   
     type Pair[+A, +B] = Tuple2[A, B]
     object Pair {
       def apply[A, B](x: A, y: B) = Tuple2(x, y)
       def unapply[A, B](x: Tuple2[A, B]): Option[Tuple2[A, B]] = Some(x)
     }
   
     type Triple[+A, +B, +C] = Tuple3[A, B, C]
     object Triple {
       def apply[A, B, C](x: A, y: B, z: C) = Tuple3(x, y, z)
       def unapply[A, B, C](x:Tuple3[A, B, C]): Option[Tuple3[A, B, C]] = Some(x)
     }
   
     class ArrowAssoc[A](x: A) {
       def -> [B](y: B): Tuple2[A, B] = Tuple2(x, y)
     }
     implicit def any2ArrowAssoc[A](x: A): ArrowAssoc[A] = new ArrowAssoc(x)
     // 印字と読み込み -----------------------------------------------
   
     def   print(x: Any) = Console.print(x)
     def   println() = Console.println()
     def   println(x: Any) = Console.println(x)
     def   printf(text: String, xs: Any*) = Console.printf(text, xs: _*)
     def   format(text: String, xs: Any*) = Console.format(text, xs: _*)
     def   readLine(): String = Console.readLine()
     def   readLine(text: String, args: Any*) = Console.readLine(text, args)
     def   readBoolean() = Console.readBoolean()
     def   readByte() = Console.readByte()
     def   readShort() = Console.readShort()
     def   readChar() = Console.readChar()
     def   readInt() = Console.readInt()
     def   readLong() = Console.readLong()
     def   readFloat() = Console.readFloat()
     def   readDouble() = Console.readDouble()
     def   readf(format: String) = Console.readf(format)
     def   readf1(format: String) = Console.readf1(format)
     def   readf2(format: String) = Console.readf2(format)
     def   readf3(format: String) = Console.readf3(format)
   
     // The ''catch-all'' implicit ----------------------------------------
   
     implicit def identity[A](x: A): A = x
   
   
     // クラス Ordered へのビュー
   
   %% @@@KSW what is ''Proxy''? It's not defined anywhere.
   %% @@@MO It's a Java interface.
     implicit def int2ordered(x: Int):Ordered[Int] = new Ordered[Int] with Proxy{
       def self: Any = x
       def compare[B >: Int <% Ordered[B]](y: B): Int = y match {
         case y1: Int =>
           if (x < y1) -1
           else if (x > y1) 1
           else 0
         case _ => -(y compare x)
       }
     }
    
     // The implementations of following methods are analogous to the last one:
     // 次のメソッドの実装は、最後の一つに類似
     implicit   def   char2ordered(x: Char): Ordered[Char] = ...
     implicit   def   long2ordered(x: Long): Ordered[Long] = ...
     implicit   def   float2ordered(x: Float): Ordered[Float] = ...
     implicit   def   double2ordered(x: Double): Ordered[Double] = ...
     implicit   def   boolean2ordered(x: Boolean): Ordered[Boolean] = ...
    
     implicit def seq2ordered[A <% Ordered[A]](xs: Array[A]): Ordered[Seq[A]] =
       new Ordered[Seq[A]] with Proxy {
         def compare[B >: Seq[A] <% Ordered[B]](that: B): Int = that match {
           case that: Seq[A] =>
             var res = 0
             val these = this.elements
             val those = that.elements
             while (res == 0 && these.hasNext)
               res = if (!those.hasNext) 1 else these.next compare those.next
           case _ => - (that compare xs)
       }
    
     implicit def string2ordered(x: String): Ordered[String] =
       new Ordered[String] with Proxy {
         def self: Any = x
         def compare[b >: String <% Ordered[b]](y: b): Int = y match {
           case y1: String => x compare y1
           case _ => -(y compare x)
         }
       }
    
    
     implicit def tuple2ordered[a1 <% Ordered[a1], a2 <% Ordered[a2]]
                               (x: Tuple2[a1, a2]): Ordered[Tuple2[a1, a2]] =
       new Ordered[Tuple2[a1, a2]] with Proxy {
         def self: Any = x
         def compare[T >: Tuple2[a1, a2] <% Ordered[T]](y: T): Int = y match {
           case y: Tuple2[a1, a2] =>
             val res = x._1 compare y._1
             if (res == 0) x._2 compare y._2
             else res
           case _ => -(y compare x)
         }
       }
    
     // Tuple3 ~ Tuple9 についても同様
     
     // クラス Seq へのビュー
     
     implicit def string2seq(str: String): Seq[Char] = new Seq[Char] {
       def length = str.length()
       def elements = Iterator.fromString(str)
       def apply(n: Int) = str.charAt(n)
       override def hashCode: Int = str.hashCode
       override def equals(y: Any): Boolean = (str == y)
       override protected def stringPrefix: String = "String"
     }
     
     // プリミティブ型から Java のボックス型へのビュー
     
     implicit   def   byte2Byte(x: Byte) = new java.lang.Byte(x)
     implicit   def   short2Short(x: Short) = new java.lang.Short(x)
     implicit   def   char2Character(x: Char) = new java.lang.Character(x)
     implicit   def   int2Integer(x: Int) = new java.lang.Integer(x)
     implicit   def   long2Long(x: Long) = new java.lang.Long(x)
     implicit   def   float2Float(x: Float) = new java.lang.Float(x)
     implicit   def   double2Double(x: Double) = new java.lang.Double(x)
     implicit   def   boolean2Boolean(x: Boolean) = new java.lang.Boolean(x)
     
     // 数値変換ビュー
     
     implicit   def   byte2short(x: Byte): Short = x.toShort
     implicit   def   byte2int(x: Byte): Int = x.toInt
     implicit   def   byte2long(x: Byte): Long = x.toLong
     implicit   def   byte2float(x: Byte): Float = x.toFloat
     implicit   def   byte2double(x: Byte): Double = x.toDouble
    
     implicit   def   short2int(x: Short): Int = x.toInt
     implicit   def   short2long(x: Short): Long = x.toLong
     implicit   def   short2float(x: Short): Float = x.toFloat
     implicit   def   short2double(x: Short): Double = x.toDouble
    
     implicit   def   char2int(x: Char): Int = x.toInt
     implicit   def   char2long(x: Char): Long = x.toLong
     implicit   def   char2float(x: Char): Float = x.toFloat
     implicit   def   char2double(x: Char): Double = x.toDouble
    
     implicit def int2long(x: Int): Long = x.toLong
     implicit def int2float(x: Int): Float = x.toFloat
     implicit def int2double(x: Int): Double = x.toDouble
    
     implicit def long2float(x: Long): Float = x.toFloat
     implicit def long2double(x: Long): Double = x.toDouble
     
     implicit def float2double(x: Float): Double = x.toDouble
   }



Bibliography

[Dra10] Iulian Dragos. Scala specialization, 2010. SID-9.

[KP07] Andrew J. Kennedy and Benjamin C. Pierce. On Decidability of Nominal Subtyping with Variance, January 2007. FOOL-WOOD '07.

[Oa04] Martin Odersky and al. An Overview of the Scala Programming Language . Technical Report IC/2004/64, EPFL Lausanne, Switzerland, 2004.

[OCRZ03] Martin Odersky, Vincent Cremet, Christine Rockl, and Matthias Zenger. A Nominal Theory of Objects with Dependent Types. In Proc. ECOOP'03, Springer LNCS, July 2003.

[Ode06] Martin Odersky. The Scala Experiment - Can We Provide Better Language Support for Component Systems? In Proc. ACM Symposium on Principles of Programming Languages, 2006.

[OZ05a] Martin Odersky and Matthias Zenger. Independently Extensible Solutions to the Expression Problem. In Proc. FOOL 12, January 2005. http://homepages.inf.ed.ac.uk/wadler/fool .

[OZ05b] Martin Odersky and Matthias Zenger. Scalable Component Abstractions. In Proc. OOPSLA, 2005.

[W3C] W3C. Extensible Markup Language (XML). http://www.w3.org/TR/REC-xml .

最終更新:2011年02月23日 18:42
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。