ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Scala 快速入门实战指南:基于 learnxinyminutes-docs 西班牙语教程的完整语法精讲

Scala 快速入门实战指南:基于 learnxinyminutes-docs 西班牙语教程的完整语法精讲 文档教程【免费下载链接】learnxinyminutes-docsCode documentation written as code! How novel and totally my idea!项目地址https://gitcode.com/gh_mirrors/le/learnxinyminutes-docs点击查看免费下载本指南以仓库中的 es/scala.mdScala 语言的西班牙语版速成教程为骨架系统梳理 Scala 从环境搭建、REPL 交互、基础语法到面向对象、模式匹配、函数式编程与隐式转换的完整知识链。读完本文你将具备独立运行 Scala REPL、阅读与编写 Scala 源码、理解集合高阶函数与 implicit 机制的实际能力并能把本文作为查漏补缺的速查手册反复使用。文档定位仓库中的 Scala 教程生态learnxinyminutes-docs 是一个以可运行的带注释代码形式速成讲解编程语言的开源文档仓库见 README.md。Scala 教程以 scala.md 为英文原版es/scala.md 是其西班牙语翻译版此外仓库内还维护着 zh-cn/scala.md、fr/scala.md、pt-br/scala.md、de/scala.md 等多语言版本便于不同语言背景的开发者对照学习。值得说明的是es/scala.md 的 frontmatterYAML 头只声明了contributors与translators字段根据 CONTRIBUTING.md 的规定非英文文章会继承英文原版的 frontmatter 值如name: Scala、filename: learnscala.scala这意味着该教程对应的可下载代码文件名为learnscala.scala。仓库中的 lint/frontmatter.py 正是用于校验这类 frontmatter 合法性的工具保证每篇文档的元数据格式统一。本文在完整保留原文全部示例与知识点的基础上修正了翻译版中的若干笔误如类名、变量名不一致并补充了实现原理层面的注释使代码可直接复制运行。环境准备安装 Scala 并启动 REPL安装步骤从 Scala 官方下载页获取对应平台的发行包解压到任意目录并将解压目录下的bin子目录加入系统的PATH环境变量在终端执行scala命令验证安装。REPLScala 的交互式解释器REPLRead-Eval-Print Loop读取-求值-打印循环是 Scala 自带的行命令解释工具与许多语言的交互式解释器类似。你可以输入任意 Scala 表达式结果会被立即求值并打印非常适合在阅读本教程时随手验证概念。$ scala scalaREPL 的几个核心特性自动编号的结果变量默认情况下你输入的每个表达式都会被保存为一个带编号的新值可直接复用scala 2 2 res0: Int 4 scala res0 2 res1: Int 6注意结果中显示的值的类型Int。Scala 是强类型语言你还可以用:type命令在不求值的情况下查看表达式的类型scala :type (true, 2.0) (Boolean, Double)会话持久化:save命令可将当前 REPL 会话保存为文件scala :save /sites/repl-test.scala加载脚本:load命令可将已有.scala文件载入 REPL 并逐条执行执行结果同样按序编号scala :load /sites/repl-test.scala Loading /sites/repl-test.scala... res2: Int 4 res3: Int 6历史记录查询:h?命令展示最近的输入历史便于回看与复跑scala :h? 1 2 2 2 res0 2 3 :save /sites/repl-test.scala 4 :load /sites/repl-test.scala 5 :h?基础语法从打印到字符串插值注释与打印// 单行注释以两个斜杠开头 /* 多行注释如上所示 可以跨越多行。 */ // println 会在打印后强制换行 println(Hola mundo!) // Hola mundo! println(10) // 10 // print 不会在打印后换行 print(Hola mundo) print(10) // Hola mundo10val 与 var不可变与可变声明值使用var或valval声明的值不可变var声明的值可变。在 Scala 中不可变性是被推崇的实践多线程环境下更安全、代码更易推理。val x 10 x 20 // 错误: reassignment to val var y 10 y 20 // 正确y 现在是 20类型推断与显式类型Scala 是静态类型语言但上面的例子没有写任何类型——这得益于语言的类型推断机制在绝大多数情况下编译器能自动推导出变量的类型因此无需每次都手动标注。当然你也可以显式声明val z: Int 10 val a: Double 1.0 // 注意 Int 到 Double 的自动转换结果是 10.0 而非 10 val b: Double 10布尔值与数学运算true false !true // false !false // true true false // false 10 5 // true // 数学运算与常规语言一致 1 1 // 2 2 - 1 // 1 5 * 3 // 15 6 / 2 // 3 6 / 4 // 1 整数除法截断小数 6.0 / 4 // 1.5 6 / 4.0 // 1.5REPL 中求值任意表达式都会返回类型与值。例如输入1 7输出为res29: Int 8表示结果是Int类型的对象值为 8。其中res29是顺序生成的变量名实际编号以你的会话为准。字符串处理Las cadenas en Scala están rodeadas por comillas dobles // Scala 字符串用双引号 a // 单引号表示字符 Char // 单引号字符串不存在 - 这会引发编译错误 // 字符串拥有 Java 的典型方法 hello world.length hello world.substring(2, 6) hello world.replace(C, 3) // 以及 Scala 特有的扩展方法见 scala.collection.immutable.StringOps hello world.take(5) // hello hello world.drop(5) // world字符串插值s / f / raw字符串插值是 Scala 的亮点之一通过前缀字母启用val n 45 sTengo $n manzanas // Tengo 45 manzanas // 可以在插值中嵌入任意表达式${...} val a Array(11, 9, 6) sMi segunda hija tiene ${a(0) - a(2)} años. // Mi segunda hija tiene 5 años. sHemos doblado la cantidad de ${n / 2.0} manzanas. // Hemos doblado la cantidad de 22.5 manzanas. sPotencia de 2: ${math.pow(2, 2)} // Potencia de 2: 4 // f 插值器支持 printf 风格格式化 fPotencia de 5: ${math.pow(5, 2)}%1.0f // Potencia de 5: 25 fRaiz cuadrada de 122: ${math.sqrt(122)}%1.4f // Raiz cuadrada de 122: 11.0454 // raw 插值器不处理转义字符原样输出 rawNueva linea: \n. Retorno: \r. // Nueva linea: \n. Retorno: \r.转义与多行字符串某些字符需要转义例如字符串内的双引号Se quedaron fuera de \Rose and Crown\ // Se quedaron fuera de Rose and Crown三引号允许字符串跨越多行并且可以自由包含单、双引号非常适合嵌入 HTML 等结构化文本val html form iddaform pPress belo, Joe/p input typesubmit /form函数定义、默认参数与匿名函数函数定义语法// def nombreFuncion(argumentos...): TipoRetorno { cuerpo... }如果你习惯传统语言请特别注意 Scala省略了return关键字函数块中的最后一个表达式就是返回值。def sumaDeCuadrados(x: Int, y: Int): Int { val x2 x * x val y2 y * y x2 y2 // 最后一个表达式作为返回值 } // 函数体为单个表达式时{} 可以省略 def sumaDeCuadradosCorta(x: Int, y: Int): Int x * x y * y sumaDeCuadrados(3, 4) // 25命名参数调用函数时可以使用参数名并以任意顺序传参def restar(x: Int, y: Int): Int x - y restar(10, 3) // 7 restar(y10, x3) // -7返回类型推断与默认参数在大多数情况下递归函数是最显著的例外函数返回类型可以省略交由类型推断处理def sq(x: Int) x * x // 编译器可推断返回类型为 Int函数支持默认参数def sumarConDefecto(x: Int, y: Int 5) x y sumarConDefecto(1, 2) // 3 sumarConDefecto(1) // 6y 使用默认值 5匿名函数与下划线占位符// 基本形式 (x: Int) x * x // 上下文明确时匿名函数的输入类型也可省略 val sq: Int Int x x * x // Int Int 表示接收 Int 返回 Int 的函数 sq(10) // 100 // 若匿名函数的每个参数都只使用一次可用下划线 _ 作占位符 val sumarUno: Int Int _ 1 val sumaRara: (Int, Int) Int (_ * 2 _ * 3) sumarUno(5) // 6 sumaRara(2, 4) // 16关于 return 的警告return关键字在 Scala 中确实存在但它只从最内层包围它的函数返回且对匿名函数无效使用不当极易引发难以定位的 bug官方教程建议避免使用。例如def foo(x: Int): Int { val funcAnon: Int Int { z if (z 5) return z // 这一行让 z 成为 foo 的返回值 else z 2 // 这一行才是 funcAnon 的返回值 } funcAnon(x) // 这一行才是 foo 的返回值 }控制流区间、循环与条件区间Range与 foreach1 to 5 // Range(1, 2, 3, 4, 5) val r 1 to 5 r.foreach(println) r foreach println // 省略点号与括号的写法 // Scala 对点号与括号相当宽容这有助于写出接近自然语言的 DSL 与 API (5 to 1 by -1) foreach (println) // 倒序区间为什么这里println不需要括号参数这与下文函数式编程一节讲到的一等函数函数可作为值传递有关——foreach接收一个函数作为参数。while 与 do-whilevar i 0 while (i 10) { println(i i); i 1 } // 再执行一次 while (i 10) { println(i i); i 1 } // 注意第一次循环后 i 已变为 10第二次 while 将不再进入循环体 i // 查看 i 的值while是经典的过程式循环顺序执行、不断修改循环变量速度很快。但上方展示的**组合子combinators与推导式for-comprehension**语义更清晰、更易并行化是 Scala 中更受推崇的写法。// do-while至少执行一次循环体 i 0 do { println(i es aún menor que 10) i 1 } while (i 10)递归与 Unit递归是 Scala以及大多数函数式语言中重复操作的惯用方式。递归函数需要显式声明返回类型因为编译器无法推断。Unit类型类似于 Java 的voiddef enseñaNumerosEnUnRango(a: Int, b: Int): Unit { print(a) if (a b) enseñaNumerosEnUnRango(a 1, b) } enseñaNumerosEnUnRango(1, 14)条件表达式Scala 的if/else是表达式有返回值因此可以直接赋值val x 10 if (x 1) println(yeah) if (x 10) println(yeah) if (x 11) println(yeah) if (x 11) println(yeah) else println(nay) println(if (x 10) yeah else nope) val text if (x 10) yeah else nope // text yeah数据结构数组、映射、集合与元组Arrayval a Array(1, 2, 3, 5, 8, 13) a(0) // Int 1 a(3) // Int 5 a(21) // 越界抛出异常Mapval m Map(fork - tenedor, spoon - cuchara, knife - cuchillo) m(fork) // java.lang.String tenedor m(spoon) // java.lang.String cuchara m(bottle) // 键不存在抛出异常 // withDefaultValue 提供缺省值兜底 val mapaSeguro m.withDefaultValue(no lo se) mapaSeguro(bottle) // java.lang.String no lo seScala 标准库中的 Map 完整 API 见scala.collection.immutable.Map的官方文档建议养成查阅 API 文档的习惯。Setval s Set(1, 3, 7) s(0) // Boolean false0 不在集合中 s(1) // Boolean true注意对 Set 使用s(元素)是成员测试返回 Boolean而非下标访问。元组Tuple元组是 Scala 中轻量级的多值打包结构(1, 2) (4, 3, 2) (1, 2, three) // 典型用途一个函数返回多个结果 val dividirEnteros (x: Int, y: Int) (x / y, x % y) dividirEnteros(10, 3) // (Int, Int) (3, 1) // 通过 _n 访问元素下标从 1 开始 val d dividirEnteros(10, 3) // (Int, Int) (3, 1) d._1 // Int 3 d._2 // Int 1 // 更优雅的方式一次性解构赋值 val (div, mod) dividirEnteros(10, 3) div // Int 3 mod // Int 1面向对象类、伴生对象、case class 与 trait顶层结构须知此前演示的都是表达式值、函数等适合在 REPL 中快速试验但不能单独存在于 Scala 源文件中——例如一个 Scala 文件里不能只写val x 5。Scala 中仅有的顶层结构是对象object类classCase 类case class特质trait类与构造器类的构造参数声明在类名之后初始化代码写在类体中class Perro(r: String) { // 构造器代码写在这里 var raza: String r // 定义方法 ladrar返回 String def ladrar Woof, woof! // 值与方法默认是 publicprotected 和 private 同样有效 private def dormir(horas: Int) println(sEstoy durmiendo $horas horas) // 抽象方法就是没有方法体的方法 // 若取消下面这行的注释Perro 就必须声明为 abstract // abstract class Perro(...) { ... } // def perseguir(algo: String): String } // 实例化原文此处有笔误统一使用 Perro 类名 val miperro new Perro(greyhound) println(miperro.raza) // greyhound println(miperro.ladrar) // Woof, woof!object 与伴生对象object关键字同时创建一个类型和该类型的单例实例。Scala 中类常常配有一个同名伴生对象类负责实例级行为伴生对象负责与所有实例相关的行为类似其他语言的静态方法。注意对象与类可以同名object Perro { def todasLasRazasConocidas List(pitbull, shepherd, retriever) def crearPerro(raza: String) new Perro(raza) }Case 类不可变数据载体初学者常纠结何时用 case class、何时用普通 class。两者的界限并不绝对但总体倾向是普通类聚焦封装、多态与行为其字段趋于私有、只暴露方法case class 的核心目的是承载不可变数据方法少且几乎没有副作用case class Persona(nombre: String, telefono: String) // 实例化 case class 不需要 new val george Persona(George, 1234) val kate Persona(Kate, 4567) // 自动获得字段访问器 george.telefono // 1234 // 自动获得基于字段的相等性比较无需重写 equals Persona(George, 1234) Persona(Kate, 1236) // false // 便捷复制copy 方法按字段复制并允许替换 val otroGeorge george.copy(telefono 9876)case class 还自动支持模式匹配见下一节并自动生成toString、hashCode等常用方法。trait接口 部分实现trait 类似 Java 接口但允许部分方法有默认实现trait 不允许有构造参数可以继承其他 trait 或无参类trait Perro { def raza: String def color: String def ladra: Boolean true // 带默认实现 def muerde: Boolean // 抽象方法由子类实现 } class SanBernardo extends Perro { val raza San Bernardo val color marrón def muerde false } val b new SanBernardo // b: SanBernardo SanBernardo3e57cd70 b.raza // res1: String San Bernardo b.ladra // res2: Boolean true b.muerde // res3: Boolean falsetrait 混入mixinwith 关键字trait 可以通过with关键字混入多个。类extends第一个 trait其余 trait 用with追加trait Ladra { def ladra: String Guau } trait Perro { def raza: String def color: String } class SanBernardo extends Perro with Ladra { val raza San Bernardo val color marrón } val b new SanBernardo // b: SanBernardo SanBernardo7b69c6ba b.ladra // res0: String Guau模式匹配远超 switch 的表达式模式匹配是 Scala 最强大的特性之一。与 C 系语言的switch不同Scala 的case不需要break匹配成功后不会落入后续分支。对 case class 做模式匹配def comparaPersona(persona: Persona): String persona match { case Persona(George, telefono) Hemos encontrado a George! Su número es telefono case Persona(Kate, telefono) Hemos encontrado a Kate! Su número es telefono case Persona(nombre, telefono) Hemos encontrado alguien : nombre , teléfono : telefono }正则表达式与模式匹配Scala 内置正则支持——对字符串调用r方法即可构造Regexval email (.*)(.*).r综合匹配示例match可以同时匹配多种形态def comparaTodo(obj: Any): String obj match { // 匹配字面值 case Hola mundo Tengo la cadena Hola mundo // 匹配类型 case x: Double Tengo un double: x // 匹配守卫guard附加条件 case x: Int if x 10000 Tengo un número muy grande! // 匹配 case class解构字段 case Persona(nombre, telefono) sTengo la información de contacto de $nombre! // 匹配正则表达式提取捕获组 case email(nombre, dominio) sTengo la dirección de correo $nombre$dominio // 匹配元组 case (a: Int, b: Double, c: String) sTengo la tupla: $a, $b, $c // 匹配集合结构 case List(1, b, c) sTengo una lista con tres elementos que empieza con 1: 1, $b, $c // 嵌套模式 case List(List((1, 2, YAY))) Tengo una lista de listas de tuplas // 通配分支默认分支 case _ Tengo un objeto desconocido }模式匹配的泛化能力实际上任何实现了unapply方法的对象都可以参与模式匹配。这一能力如此强大以至于 Scala 允许你把整个函数定义成一组模式偏函数val funcPatron: Persona String { case Persona(George, telefono) sTeléfono de George: $telefono case Persona(nombre, telefono) sTeléfono de una persona aleatoria: $telefono }函数式编程高阶函数、组合子与 for 推导式函数是一等公民Scala 的方法与函数可以作为返回值也可以作为参数传给其他函数val suma10: Int Int _ 10 // 接收 Int 返回 Int 的函数 List(1, 2, 3) map suma10 // List(11, 12, 13) —— suma10 被应用到每个元素 // 匿名函数可以直接代替具名函数 List(1, 2, 3) map (x x 10) // 匿名函数只有一个参数时可用下划线占位 List(1, 2, 3) map (_ 10) // 若匿名函数块与所调函数都只用一个参数连下划线都可省略 List(Dom, Bob, Natalia) foreach println组合子map / filter / reduce// 沿用前文的 val s Set(1, 3, 7) 与函数 sq s.map(sq) // 对每个元素应用 sq val sCuadrado s.map(sq) sCuadrado.filter(_ 10) // 过滤不满足谓词的元素 sCuadrado.reduce(_ _) // 归约两两合并 // filter 接收谓词A Boolean选出满足条件的元素 List(1, 2, 3) filter (_ 2) // List(3) case class Persona(nombre: String, edad: Int) List( Persona(nombre Dom, edad 23), Persona(nombre Bob, edad 30) ).filter(_.edad 25) // List(Persona(Bob, 30))foreach面向副作用的遍历部分集合如 List提供foreach方法其参数是返回Unit的函数即void 方法val unaListaDeNumeros List(1, 2, 3, 4, 10, 20, 100) unaListaDeNumeros foreach (x println(x)) unaListaDeNumeros foreach printlnfor 推导式for-comprehensionfor { n - s } yield sq(n) val nCuadrado2 for { n - s } yield sq(n) for { n - nCuadrado2 if n 10 } yield n for { n - s; nCuadrado n * n if nCuadrado 10 } yield nCuadrado重要澄清这些不是循环。循环的语义是重复执行而 for 推导式定义的是两组数据之间的映射关系因此可以用if过滤、用yield产出新集合天然适合并行化。隐式机制implicits理解而非滥用严重警告implicits 是 Scala 中最强大也最容易滥用的特性。初学者应抵制先使用它的冲动直到不仅理解其原理、也理解围绕它的最佳实践。本节之所以保留是因为 Scala 生态中的库几乎无处不在使用 implicits——不读懂它们就无法使用任何有分量的库。本节目标是理解并配合implicits而不是鼓励你自行定义。声明隐式值任何值val、函数、对象等都可以用implicit关键字声明为隐式。沿用上文Perro类implicit val miEnteroImplicito 100 implicit def miFuncionImplicita(raza: String) new Perro(Golden raza) // implicit 本身不改变值的普通用法 miEnteroImplicito 2 // 102 miFuncionImplicita(Pitbull).raza // Golden Pitbull隐式参数当代码需要一个隐式值区别在于这些值现在可以被其他需要隐式值的代码选用。典型场景是函数的隐式参数列表def enviaSaludos(aQuien: String)(implicit cuantos: Int) sHola $aQuien, $cuantos saludos a ti y a los tuyos! // 显式传值时函数行为与普通函数无异 enviaSaludos(John)(1000) // Hola John, 1000 saludos a ti y a los tuyos! // 省略隐式参数时编译器自动采用同类型的隐式值此处为 miEnteroImplicito enviaSaludos(Jane) // Hola Jane, 100 saludos a ti y a los tuyos!隐式参数使我们得以在 Scala 中模拟其他函数式语言的类型类type class。该用法极其常见以至于有专属语法糖——下面两行含义相同// def fooT ... // def foo[T : C] ...隐式转换为对象补方法编译器查找隐式的另一种情形当你写obj.metodo(...)而obj并没有metodo方法时如果作用域中存在A B的隐式转换A 是 obj 的类型B 拥有metodo该转换会被自动应用。于是有了miFuncionImplicita后我们可以直接对字符串调用 Perro 的方法Retriever.raza // Golden Retriever Sheperd.ladra // Woof, woof!这里字符串先经miFuncionImplicita被转换为Perro再调用对应方法。这是极为强大的能力但绝不可轻率使用——事实上定义隐式函数时编译器通常会给出警告除非你确实清楚自己在做什么否则不要这样做。杂项导入、程序入口与文件 I/Oimport 的各种形式// 导入单个类 import scala.collection.immutable.List // 通配导入子包所有内容 import scala.collection.immutable._ // 一行导入多个类 import scala.collection.immutable.{List, Map} // 用 重命名导入 import scala.collection.immutable.{List ImmutableList} // 导入除个别类外的全部下面排除了 Map 和 Set import scala.collection.immutable.{Map _, Set _, _} // Java 类同样可以用 Scala 语法导入 import java.swing.{JFrame, JWindow}程序入口与编译Scala 程序的入口点定义在object中包含一个main方法object Application { def main(args: Array[String]): Unit { // 你的代码写在这里 } }一个.scala文件可以包含多个类与对象使用scalac编译器编译。文件读写逐行读取文件import scala.io.Source for(line - Source.fromFile(miarchivo.txt).getLines()) println(line)写文件则使用 Java 的PrintWriterval writer new PrintWriter(miarchivo.txt) writer.write(Escribiendo linea por linea util.Properties.lineSeparator) writer.write(Otra linea util.Properties.lineSeparator) writer.close()学习路径与仓库延伸资源对照阅读英文原版 scala.md可确认翻译版中若干类名/变量名的原始写法中文读者可直接参考 zh-cn/scala.md 的中文翻译版若想为其他语言补充翻译CONTRIBUTING.md 说明了 frontmatter 字段规范contributors、translators、filename等lint/frontmatter.py 则提供了自动化校验这些元数据的参考实现教程正文对应的可下载代码文件名由 frontmatter 的filename: learnscala.scala指定可将全文代码块拼接为单文件后用scalac编译、scala运行。实践建议不必死记硬背语法细节——把 REPL 当作草稿纸随时用:type验证类型推断、用:load回放脚本遇到集合操作优先想map/filter/reduce组合子而非手写循环在设计数据结构时优先考虑case class的不可变模型。这样很快就能从看得懂过渡到写得顺。赞分享文档教程【免费下载链接】learnxinyminutes-docsCode documentation written as code! How novel and totally my idea!项目地址https://gitcode.com/gh_mirrors/le/learnxinyminutes-docs点击查看免费下载相关推荐learnxinyminutes-docs 西班牙语版 JavaScript 入门指南从基础语法到原型链的完整实战解析learnxinyminutes docs 西班牙语版 JavaScript 入门指南从基础语法到原型链的完整实战解析 本指南以 learnxinyminut文档教程CoffeeScript 入门指南从西班牙语教程看编译到 JavaScript 的语法速览learnxinyminutes-docsCoffeeScript 入门指南从西班牙语教程看编译到 JavaScript 的语法速览learnxinyminutes docs 导读 本文以 lea文档教程Johnny-Five 使用 Adafruit Ultimate GPS Breakout 实现 Arduino GPS 定位Johnny Five 使用 Adafruit Ultimate GPS Breakout 实现 Arduino GPS 定位 导读 本文基于 Johnny F文档教程上一篇终极AWS安全指南如何用aws-vault实现MFA集成保护下一篇AceGPT-13B-chat模型架构深度剖析基于LLaMA2的阿拉伯语优化方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表