用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/cxcscmu/SkillLearnBench --skill scala-circe-json命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
基于 SOC 职业分类
正在显示 SKILL.md
| name | scala-circe-json |
| description | Working with Circe JSON library in Scala for type-safe JSON processing |
Circe is the standard type-safe JSON library in Scala. It provides:
Json typeAdd to build.sbt:
libraryDependencies ++= Seq(
"io.circe" %% "circe-core" % "0.14.5",
"io.circe" %% "circe-parser" % "0.14.5",
"io.circe" %% "circe-generic" % "0.14.5"
)
import io.circe.parser._
import io.circe._
// Parse from string
val jsonString = """{"name": "Alice", "age": 30}"""
val result: Either[io.circe.ParsingFailure, Json] = parse(jsonString)
// Safe extraction
result match {
case Right(json) => println(s"Parsed: $json")
case Left(error) => println(s"Parse error: $error")
}
// Or with Try
val json: scala.util.Try[Json] = parse(jsonString).toTry
import io.circe.syntax._
// From primitives
val str = Json.fromString("hello")
val num = Json.fromInt(42)
val bool = Json.fromBoolean(true)
val null_val = Json.Null
// Object (using syntax extension)
val obj = Json.obj(
"name" -> Json.fromString("Alice"),
"age" -> Json.fromInt(30)
)
// Array
val arr = Json.arr(
Json.fromInt(1),
Json.fromInt(2),
Json.fromInt(3)
)
// Using tuple extension (cleaner)
val obj = Json.obj(
"name" -> "Alice".asJson,
"age" -> 30.asJson,
"scores" -> List(90, 85, 88).asJson
)
val json = Json.obj(
"name" -> "Alice".asJson,
"age" -> 30.asJson
)
// Type checks
json.isObject // true
json.isArray // false
json.isNull // false
// Conversions
json.asObject // Option[JsonObject]
json.asArray // Option[Vector[Json]]
json.asString // Option[String]
json.asNumber // Option[JsonNumber]
json.asBoolean // Option[Boolean]
// Unsafe conversion (throws)
json.asObject.get
Cursors provide safe, composable navigation (like XPath):
import io.circe.{Json, HCursor}
val json = parse("""
{
"person": {
"name": "Alice",
"addresses": [
{"city": "NYC"},
{"city": "Boston"}
]
}
}
""").getOrElse(Json.Null)
// Creating cursor
val cursor: HCursor = json.hcursor
// Navigation
val name: Either[DecodingFailure, String] =
cursor
.downField("person")
.downField("name")
.as[String]
// Navigate arrays
val firstCity: Either[DecodingFailure, String] =
cursor
.downField("person")
.downField("addresses")
.downArray
.downField("city")
.as[String]
// Optional navigation (returns Json)
cursor.downField("person").downField("name").focus // Option[Json]
val cursor = json.hcursor
// Navigation
cursor.downField("fieldName") // Navigate to field
cursor.downArray // Navigate to first array element
cursor.up // Go to parent
cursor.left // Move to previous array element
cursor.right // Move to next array element
// Extraction
cursor.focus // Option[Json] - current value
cursor.as[String] // Either[DecodingFailure, String]
// Checking
cursor.succeeded // Boolean - did navigation succeed?
import io.circe._, io.circe.generic.semiauto._
case class Person(name: String, age: Int)
// Automatic codec generation
implicit val encoder: Encoder[Person] = deriveEncoder[Person]
implicit val decoder: Decoder[Person] = deriveDecoder[Person]
// Usage
val person = Person("Alice", 30)
val json = person.asJson
val decoded = json.as[Person] // Either[DecodingFailure, Person]
implicit val customEncoder: Encoder[Person] = new Encoder[Person] {
def apply(p: Person): Json = Json.obj(
"fullName" -> Json.fromString(p.name),
"years" -> Json.fromInt(p.age)
)
}
implicit val customDecoder: Decoder[Person] = new Decoder[Person] {
def apply(c: HCursor): Decoder.Result[Person] = for {
name <- c.downField("fullName").as[String]
age <- c.downField("years").as[Int]
} yield Person(name, age)
}
For recursive types like JSON itself:
// Representing JSON recursively
sealed trait JsonValue
case class JString(value: String) extends JsonValue
case class JNumber(value: Double) extends JsonValue
case class JBoolean(value: Boolean) extends JsonValue
case object JNull extends JsonValue
case class JArray(value: Vector[JsonValue]) extends JsonValue
case class JObject(value: Map[String, JsonValue]) extends JsonValue
// Or use Circe's Json type directly (which IS recursive)
val json: Json = Json.obj(
"data" -> Json.arr(
Json.obj("id" -> 1.asJson),
Json.obj("id" -> 2.asJson)
)
)
import io.circe.Printer
val json = Json.obj("name" -> "Alice".asJson, "age" -> 30.asJson)
// Compact
json.toString()
// {"name":"Alice","age":30}
// Pretty printed
val printer = Printer.spaces2 // 2-space indent
println(printer.print(json))
// {
// "name" : "Alice",
// "age" : 30
// }
// Custom printer
val customPrinter = Printer(
dropNullValues = false,
indent = " "
)
def getValueAtPath(json: Json, path: String): Option[Json] = {
val parts = path.split("\\.")
parts.foldLeft(Option(json)) { case (current, part) =>
current.flatMap { j =>
if (j.isObject) {
j.hcursor.downField(part).focus
} else if (j.isArray) {
part.toIntOption.flatMap { idx =>
j.asArray.flatMap(_.lift(idx))
}
} else {
None
}
}
}
}
// Usage
val json = parse("""{"person": {"name": "Alice", "scores": [90, 85]}}""").getOrElse(Json.Null)
val name = getValueAtPath(json, "person.name") // Some("Alice")
val score = getValueAtPath(json, "person.scores.0") // Some(90)
val missing = getValueAtPath(json, "person.email") // None
import io.circe.Json
import io.circe.syntax._
class JsonTokenizer(pretty: Boolean = false) {
def tokenize(json: Json): Token = {
val jsonStr = if (pretty) {
Printer.spaces2.print(json)
} else {
json.toString()
}
Token(jsonStr, TokenType.STRUCTURED, Map("json" -> true.asJson))
}
def tokenizePath(json: Json, path: String): Option[Token] = {
getValueAtPath(json, path).map(tokenize)
}
private def getValueAtPath(json: Json, path: String): Option[Json] = {
val parts = path.split("\\.")
parts.foldLeft(Option(json)) { case (current, part) =>
current.flatMap { j =>
if (j.isObject) j.hcursor.downField(part).focus
else if (j.isArray) {
part.toIntOption.flatMap(idx => j.asArray.flatMap(_.lift(idx)))
} else None
}
}
}
}
Unlike Python's duck typing with JSON:
# Python - runtime errors possible
data = {"name": "Alice"}
age = data["age"] # KeyError!
// Scala - compile-time safety
val json = parse("""{"name": "Alice"}""").getOrElse(Json.Null)
val age: Option[Int] = json.hcursor.downField("age").as[Int].toOption
// Type mismatch caught at compile time
// Manual approach (error-prone)
val jsonStr = s"""{"value": "$value", "type": "$tokenType"}"""
// Circe approach (safe, composable)
val token = Token(value, tokenType)
val json = token.asJson // With derived encoders