From 5045d998a3b7773658b041d49495afd22371936d Mon Sep 17 00:00:00 2001 From: "Yonghyun Kim (Freddy)" Date: Sat, 10 Jan 2026 22:11:12 +0900 Subject: [PATCH] docs: add array shorthand syntax `T[]` documentation and changelog - Update arrays-and-hashes docs with `String[]` syntax examples (en, ja, ko) - Update built-in-generics with array shorthand examples - Add v0.0.43 to changelog with array shorthand feature - Update cheatsheet with new syntax - Update optional-rest-parameters examples - Both `String[]` and `Array` syntaxes are documented --- docs/learn/basics/basic-types.md | 2 +- .../learn/everyday-types/arrays-and-hashes.md | 149 ++++++++-------- .../functions/optional-rest-parameters.md | 30 ++-- docs/learn/generics/built-in-generics.md | 166 +++++++++--------- docs/project/changelog.md | 36 +++- docs/reference/built-in-types.md | 56 +++--- docs/reference/cheatsheet.md | 35 ++-- .../learn/everyday-types/arrays-and-hashes.md | 134 +++++++------- .../functions/optional-rest-parameters.md | 28 +-- .../current/project/changelog.md | 4 +- .../learn/everyday-types/arrays-and-hashes.md | 134 +++++++------- .../functions/optional-rest-parameters.md | 28 +-- .../current/project/changelog.md | 4 +- 13 files changed, 424 insertions(+), 382 deletions(-) diff --git a/docs/learn/basics/basic-types.md b/docs/learn/basics/basic-types.md index 1b5564c..1ec43bd 100644 --- a/docs/learn/basics/basic-types.md +++ b/docs/learn/basics/basic-types.md @@ -175,7 +175,7 @@ speed_of_light: Float = 2.998e8 # 299,800,000 ### Float Arithmetic ```trb title="float_math.trb" -def calculate_average(values: Array): Float +def calculate_average(values: Float[]): Float sum = 0.0 values.each do |v| sum += v diff --git a/docs/learn/everyday-types/arrays-and-hashes.md b/docs/learn/everyday-types/arrays-and-hashes.md index 4e5550b..446535b 100644 --- a/docs/learn/everyday-types/arrays-and-hashes.md +++ b/docs/learn/everyday-types/arrays-and-hashes.md @@ -13,22 +13,22 @@ Arrays and hashes are the most commonly used collection types in T-Ruby. They al ## Array Types -Arrays in T-Ruby use generic type syntax: `Array`, where `T` is the type of elements in the array. +Arrays in T-Ruby use shorthand syntax: `T[]`, where `T` is the type of elements in the array. You can also use the generic syntax `Array`. ### Basic Array Syntax ```trb title="array_basics.trb" # Array of integers -numbers: Array = [1, 2, 3, 4, 5] +numbers: Integer[] = [1, 2, 3, 4, 5] # Array of strings -names: Array = ["Alice", "Bob", "Charlie"] +names: String[] = ["Alice", "Bob", "Charlie"] # Array of floats -prices: Array = [9.99, 14.99, 19.99] +prices: Float[] = [9.99, 14.99, 19.99] # Empty array (type annotation required) -items: Array = [] +items: String[] = [] ``` ### Type Inference with Arrays @@ -36,70 +36,70 @@ items: Array = [] When initializing with values, T-Ruby can infer the array type: ```trb title="array_inference.trb" -# Type is inferred as Array +# Type is inferred as Integer[] numbers = [1, 2, 3, 4, 5] -# Type is inferred as Array +# Type is inferred as String[] names = ["Alice", "Bob", "Charlie"] # For empty arrays, you must provide a type annotation -items: Array = [] +items: String[] = [] ``` ### Array Operations ```trb title="array_operations.trb" -def add_item(items: Array, item: String): Array +def add_item(items: String[], item: String): String[] items << item items end -def get_first(items: Array): String | nil +def get_first(items: String[]): String? items.first end -def get_last(items: Array): Integer | nil +def get_last(items: Integer[]): Integer? items.last end -def array_length(items: Array): Integer +def array_length(items: String[]): Integer items.length end # Usage -list: Array = ["apple", "banana"] +list: String[] = ["apple", "banana"] updated = add_item(list, "cherry") # ["apple", "banana", "cherry"] -first: String | nil = get_first(list) # "apple" +first: String? = get_first(list) # "apple" count: Integer = array_length(list) # 3 ``` ### Accessing Array Elements ```trb title="array_access.trb" -def get_at_index(items: Array, index: Integer): String | nil +def get_at_index(items: String[], index: Integer): String? items[index] end -def get_slice(items: Array, start: Integer, length: Integer): Array +def get_slice(items: Integer[], start: Integer, length: Integer): Integer[] items[start, length] end -def get_range(items: Array, range: Range): Array +def get_range(items: String[], range: Range): String[] items[range] end -fruits: Array = ["apple", "banana", "cherry", "date"] +fruits: String[] = ["apple", "banana", "cherry", "date"] -item: String | nil = get_at_index(fruits, 0) # "apple" -slice: Array = get_slice([1, 2, 3, 4, 5], 1, 3) # [2, 3, 4] -subset: Array = get_range(fruits, 1..2) # ["banana", "cherry"] +item: String? = get_at_index(fruits, 0) # "apple" +slice: Integer[] = get_slice([1, 2, 3, 4, 5], 1, 3) # [2, 3, 4] +subset: String[] = get_range(fruits, 1..2) # ["banana", "cherry"] ``` ### Iterating Over Arrays ```trb title="array_iteration.trb" -def sum_numbers(numbers: Array): Integer +def sum_numbers(numbers: Integer[]): Integer total = 0 numbers.each do |n| total += n @@ -107,47 +107,47 @@ def sum_numbers(numbers: Array): Integer total end -def double_values(numbers: Array): Array +def double_values(numbers: Integer[]): Integer[] numbers.map { |n| n * 2 } end -def filter_positive(numbers: Array): Array +def filter_positive(numbers: Integer[]): Integer[] numbers.select { |n| n > 0 } end -def find_first_even(numbers: Array): Integer | nil +def find_first_even(numbers: Integer[]): Integer? numbers.find { |n| n % 2 == 0 } end total: Integer = sum_numbers([1, 2, 3, 4, 5]) # 15 -doubled: Array = double_values([1, 2, 3]) # [2, 4, 6] -positive: Array = filter_positive([-1, 2, -3, 4]) # [2, 4] -even: Integer | nil = find_first_even([1, 3, 4, 5]) # 4 +doubled: Integer[] = double_values([1, 2, 3]) # [2, 4, 6] +positive: Integer[] = filter_positive([-1, 2, -3, 4]) # [2, 4] +even: Integer? = find_first_even([1, 3, 4, 5]) # 4 ``` ### Array Transformation Methods ```trb title="array_transform.trb" -def join_strings(items: Array, separator: String): String +def join_strings(items: String[], separator: String): String items.join(separator) end -def reverse_array(items: Array): Array +def reverse_array(items: Integer[]): Integer[] items.reverse end -def sort_numbers(numbers: Array): Array +def sort_numbers(numbers: Integer[]): Integer[] numbers.sort end -def unique_items(items: Array): Array +def unique_items(items: String[]): String[] items.uniq end joined: String = join_strings(["a", "b", "c"], "-") # "a-b-c" -reversed: Array = reverse_array([1, 2, 3]) # [3, 2, 1] -sorted: Array = sort_numbers([3, 1, 4, 2]) # [1, 2, 3, 4] -unique: Array = unique_items(["a", "b", "a", "c"]) # ["a", "b", "c"] +reversed: Integer[] = reverse_array([1, 2, 3]) # [3, 2, 1] +sorted: Integer[] = sort_numbers([3, 1, 4, 2]) # [1, 2, 3, 4] +unique: String[] = unique_items(["a", "b", "a", "c"]) # ["a", "b", "c"] ``` ### Nested Arrays @@ -156,11 +156,11 @@ Arrays can contain other arrays: ```trb title="nested_arrays.trb" # 2D array (array of arrays) -def create_grid(rows: Integer, cols: Integer): Array> - grid: Array> = [] +def create_grid(rows: Integer, cols: Integer): Integer[][] + grid: Integer[][] = [] rows.times do |r| - row: Array = [] + row: Integer[] = [] cols.times do |c| row << (r * cols + c) end @@ -170,12 +170,12 @@ def create_grid(rows: Integer, cols: Integer): Array> grid end -def get_cell(grid: Array>, row: Integer, col: Integer): Integer | nil +def get_cell(grid: Integer[][], row: Integer, col: Integer): Integer? return nil if grid[row].nil? grid[row][col] end -matrix: Array> = create_grid(3, 3) +matrix: Integer[][] = create_grid(3, 3) # [[0, 1, 2], [3, 4, 5], [6, 7, 8]] value = get_cell(matrix, 1, 1) # 4 @@ -269,11 +269,11 @@ def print_hash(hash: Hash) end end -def get_keys(hash: Hash): Array +def get_keys(hash: Hash): String[] hash.keys end -def get_values(hash: Hash): Array +def get_values(hash: Hash): Integer[] hash.values end @@ -283,8 +283,8 @@ end scores: Hash = { "alice" => 95, "bob" => 88 } -keys: Array = get_keys(scores) # ["alice", "bob"] -values: Array = get_values({ a: 1, b: 2 }) # [1, 2] +keys: String[] = get_keys(scores) # ["alice", "bob"] +values: Integer[] = get_values({ a: 1, b: 2 }) # [1, 2] doubled: Hash = transform_values({ a: 5, b: 10 }) # { a: 10, b: 20 } @@ -375,11 +375,11 @@ Collections can hold multiple types using union types: ```trb title="array_unions.trb" # Array that can contain strings or integers -def create_mixed_array(): Array +def create_mixed_array(): (String | Integer)[] ["alice", 42, "bob", 100] end -def sum_numbers_from_mixed(items: Array): Integer +def sum_numbers_from_mixed(items: (String | Integer)[]): Integer total = 0 items.each do |item| @@ -391,7 +391,7 @@ def sum_numbers_from_mixed(items: Array): Integer total end -mixed: Array = create_mixed_array() +mixed: (String | Integer)[] = create_mixed_array() sum: Integer = sum_numbers_from_mixed(mixed) # 142 ``` @@ -435,7 +435,7 @@ Here's a comprehensive example combining arrays and hashes: ```trb title="data_processing.trb" class DataProcessor def initialize() - @records: Array> = [] + @records: Hash[] = [] end def add_record(name: String, age: Integer, score: Integer) @@ -447,8 +447,8 @@ class DataProcessor @records << record end - def get_all_names(): Array - names: Array = [] + def get_all_names(): String[] + names: String[] = [] @records.each do |record| name = record[:name] @@ -475,8 +475,8 @@ class DataProcessor total.to_f / @records.length end - def get_top_scorers(threshold: Integer): Array - top_scorers: Array = [] + def get_top_scorers(threshold: Integer): String[] + top_scorers: String[] = [] @records.each do |record| score = record[:score] @@ -490,8 +490,8 @@ class DataProcessor top_scorers end - def group_by_age(): Hash> - groups: Hash> = {} + def group_by_age(): Hash + groups: Hash = {} @records.each do |record| age = record[:age] @@ -535,16 +535,16 @@ processor.add_record("Alice", 25, 95) processor.add_record("Bob", 30, 88) processor.add_record("Charlie", 25, 92) -names: Array = processor.get_all_names() +names: String[] = processor.get_all_names() # ["Alice", "Bob", "Charlie"] avg: Float = processor.get_average_score() # 91.67 -top: Array = processor.get_top_scorers(90) +top: String[] = processor.get_top_scorers(90) # ["Alice", "Charlie"] -by_age: Hash> = processor.group_by_age() +by_age: Hash = processor.group_by_age() # { 25 => ["Alice", "Charlie"], 30 => ["Bob"] } stats: Hash = processor.get_statistics() @@ -556,8 +556,8 @@ stats: Hash = processor.get_statistics() ### Building Arrays Dynamically ```trb title="array_building.trb" -def build_range(start: Integer, stop: Integer): Array - result: Array = [] +def build_range(start: Integer, stop: Integer): Integer[] + result: Integer[] = [] i = start while i <= stop @@ -569,10 +569,10 @@ def build_range(start: Integer, stop: Integer): Array end def filter_and_transform( - numbers: Array, + numbers: Integer[], threshold: Integer -): Array - result: Array = [] +): String[] + result: String[] = [] numbers.each do |n| if n > threshold @@ -583,15 +583,15 @@ def filter_and_transform( result end -range: Array = build_range(1, 5) # [1, 2, 3, 4, 5] -filtered: Array = filter_and_transform([10, 5, 20, 3], 8) +range: Integer[] = build_range(1, 5) # [1, 2, 3, 4, 5] +filtered: String[] = filter_and_transform([10, 5, 20, 3], 8) # ["High: 10", "High: 20"] ``` ### Building Hashes Dynamically ```trb title="hash_building.trb" -def count_occurrences(words: Array): Hash +def count_occurrences(words: String[]): Hash counts: Hash = {} words.each do |word| @@ -607,7 +607,7 @@ def count_occurrences(words: Array): Hash end def index_by_property( - items: Array>, + items: Hash[], key: Symbol ): Hash> index: Hash> = {} @@ -622,7 +622,7 @@ def index_by_property( index end -words: Array = ["apple", "banana", "apple", "cherry", "banana", "apple"] +words: String[] = ["apple", "banana", "apple", "cherry", "banana", "apple"] counts: Hash = count_occurrences(words) # { "apple" => 3, "banana" => 2, "cherry" => 1 } ``` @@ -636,31 +636,31 @@ counts: Hash = count_occurrences(words) # items = [] # Error! # Always annotate empty collections -items: Array = [] +items: String[] = [] config: Hash = {} ``` ### Mutating Collections ```trb title="mutation.trb" -def add_item_wrong(items: Array): Array +def add_item_wrong(items: String[]): String[] # This mutates the original array items << "new" items end -def add_item_safe(items: Array): Array +def add_item_safe(items: String[]): String[] # Create a copy first new_items = items.dup new_items << "new" new_items end -original: Array = ["a", "b"] +original: String[] = ["a", "b"] result1 = add_item_wrong(original) # original is now ["a", "b", "new"]! -original2: Array = ["a", "b"] +original2: String[] = ["a", "b"] result2 = add_item_safe(original2) # original2 is still ["a", "b"] ``` @@ -685,11 +685,12 @@ end Arrays and Hashes are essential collection types in T-Ruby: -- **Arrays** use `Array` syntax for homogeneous collections +- **Arrays** use `T[]` syntax (shorthand) or `Array` for homogeneous collections - **Hashes** use `Hash` syntax for key-value pairs - **Type inference** works for non-empty collections - **Empty collections** always require type annotations -- **Union types** allow mixed-type collections +- **Union types** allow mixed-type collections: `(String | Integer)[]` +- **Nested arrays** use multiple brackets: `Integer[][]` - **Nested structures** combine arrays and hashes for complex data Understanding these collection types is crucial for organizing data in T-Ruby applications. In the next chapter, you'll learn about union types in more detail. diff --git a/docs/learn/functions/optional-rest-parameters.md b/docs/learn/functions/optional-rest-parameters.md index fb97f96..640d6cd 100644 --- a/docs/learn/functions/optional-rest-parameters.md +++ b/docs/learn/functions/optional-rest-parameters.md @@ -68,15 +68,15 @@ send_email("bob@example.com", "Meeting", "team@example.com") Rest parameters collect multiple arguments into an array. Type the array's element type: ```trb title="rest.trb" -def sum(*numbers: Array): Integer +def sum(*numbers: Integer[]): Integer numbers.reduce(0, :+) end -def concat_strings(*strings: Array): String +def concat_strings(*strings: String[]): String strings.join(" ") end -def log_messages(level: String, *messages: Array): void +def log_messages(level: String, *messages: String[]): void messages.each do |msg| puts "[#{level}] #{msg}" end @@ -96,7 +96,7 @@ log_messages("INFO", "App started", "Database connected", "Ready") # [INFO] Ready ``` -The type annotation `*numbers: Array` means "zero or more Integer arguments collected into an array". +The type annotation `*numbers: Integer[]` means "zero or more Integer arguments collected into an array". ## Combining Optional and Rest Parameters @@ -107,7 +107,7 @@ def create_team( name: String, leader: String, active: Boolean = true, - *members: Array + *members: String[] ): Team Team.new( name: name, @@ -155,7 +155,7 @@ def create_post({ title: String, content: String, published: Boolean = false, - tags: Array = [] + tags: String[] = [] }): Post Post.new( title: title, @@ -188,7 +188,7 @@ interface PostOptions title: String content: String published?: Boolean # ? marks optional - tags?: Array + tags?: String[] end def create_post({ title:, content:, published: false, tags: [] }: PostOptions): Post @@ -292,7 +292,7 @@ You can combine all parameter types, but they must follow this order: def complex_function( required_pos: String, # 1. Required positional optional_pos: Integer = 0, # 2. Optional positional - *rest_args: Array, # 3. Rest parameter + *rest_args: String[], # 3. Rest parameter { required_kw: Boolean, # 4. Required keyword optional_kw: String = "default" # 5. Optional keyword @@ -339,7 +339,7 @@ class HTTPRequestBuilder end # Required + rest parameters - def delete(*urls: Array): Array + def delete(*urls: String[]): Response[] urls.map { |url| make_request("DELETE", url, nil, {}) } end @@ -429,7 +429,7 @@ class Logger end # Multiple messages with rest parameter - def log_many(level: String, *messages: Array): void + def log_many(level: String, *messages: String[]): void messages.each { |msg| log(msg, level) } end @@ -440,7 +440,7 @@ class Logger end # Flexible debug logging - def debug(*messages: Array, **context: Hash): void + def debug(*messages: String[], **context: Hash): void messages.each do |msg| ctx_str = context.empty? ? "" : " (#{context.map { |k, v| "#{k}=#{v}" }.join(", ")})" puts "[DEBUG] #{msg}#{ctx_str}" @@ -500,8 +500,8 @@ def build_email({ subject: String, from: String = "noreply@example.com", reply_to: String? = nil, - cc: Array = [], - bcc: Array = [] + cc: String[] = [], + bcc: String[] = [] }): Email Email.new(to, subject, from, reply_to, cc, bcc) end @@ -513,7 +513,7 @@ email = build_email(to: "alice@example.com", subject: "Hello") ### Variadic Factory Functions (Rest + Keyword Arguments) ```trb title="factory.trb" -def create_users(*names: Array, { role: String = "user" }): Array +def create_users(*names: String[], { role: String = "user" }): User[] names.map { |name| User.new(name: name, role: role) } end @@ -542,7 +542,7 @@ Optional and rest parameters give your functions flexibility while maintaining t |--------|-------------|--------------| | `(x: Type)` | Positional argument | `foo("hi")` | | `(x: Type = default)` | Optional positional | `foo()` or `foo("hi")` | -| `(*args: Array)` | Rest parameter | `foo("a", "b", "c")` | +| `(*args: Type[])` | Rest parameter | `foo("a", "b", "c")` | | `({ x: Type })` | Keyword argument | `foo(x: "hi")` | | `(config: { x: Type })` | Hash literal | `foo(config: { x: "hi" })` | | `(**kwargs: Hash)` | Keyword rest | `foo(a: 1, b: 2)` | diff --git a/docs/learn/generics/built-in-generics.md b/docs/learn/generics/built-in-generics.md index cd3caf2..a0f0efd 100644 --- a/docs/learn/generics/built-in-generics.md +++ b/docs/learn/generics/built-in-generics.md @@ -11,24 +11,24 @@ description: Array, Hash, and other built-in generic types T-Ruby comes with several built-in generic types that you'll use every day. These types are parameterized to work with any type while providing type safety. Understanding how to use these built-in generics is essential for writing type-safe T-Ruby code. -## Array\ +## Array\ (or T[]) -The most commonly used generic type is `Array`, representing an array of elements of type `T`. +The most commonly used generic type is `Array`, representing an array of elements of type `T`. T-Ruby also supports the shorthand syntax `T[]`. ### Basic Array Usage ```trb -# Explicitly typed arrays -numbers: Array = [1, 2, 3, 4, 5] -names: Array = ["Alice", "Bob", "Charlie"] -flags: Array = [true, false, true] +# Explicitly typed arrays (shorthand syntax) +numbers: Integer[] = [1, 2, 3, 4, 5] +names: String[] = ["Alice", "Bob", "Charlie"] +flags: Boolean[] = [true, false, true] # Type inference works too -inferred_numbers = [1, 2, 3] # Array -inferred_names = ["Alice", "Bob"] # Array +inferred_numbers = [1, 2, 3] # Integer[] +inferred_names = ["Alice", "Bob"] # String[] # Empty arrays need explicit types -empty_numbers: Array = [] +empty_numbers: Integer[] = [] empty_users = Array.new ``` @@ -37,40 +37,40 @@ empty_users = Array.new All standard array operations preserve type safety: ```trb -numbers: Array = [1, 2, 3, 4, 5] +numbers: Integer[] = [1, 2, 3, 4, 5] # Accessing elements -first: Integer | nil = numbers[0] # 1 -last: Integer | nil = numbers[-1] # 5 -out_of_bounds: Integer | nil = numbers[100] # nil +first: Integer? = numbers[0] # 1 +last: Integer? = numbers[-1] # 5 +out_of_bounds: Integer? = numbers[100] # nil # Adding elements -numbers.push(6) # Array -numbers << 7 # Array -numbers.unshift(0) # Array +numbers.push(6) # Integer[] +numbers << 7 # Integer[] +numbers.unshift(0) # Integer[] # Removing elements -popped: Integer | nil = numbers.pop # Removes and returns last -shifted: Integer | nil = numbers.shift # Removes and returns first +popped: Integer? = numbers.pop # Removes and returns last +shifted: Integer? = numbers.shift # Removes and returns first # Checking contents contains_three: Boolean = numbers.include?(3) # true -index: Integer | nil = numbers.index(3) # 2 +index: Integer? = numbers.index(3) # 2 ``` ### Array Mapping and Transformation -Mapping transforms an `Array` into an `Array`: +Mapping transforms a `T[]` into a `U[]`: ```trb # Map integers to strings -numbers: Array = [1, 2, 3, 4, 5] -strings: Array = numbers.map { |n| n.to_s } +numbers: Integer[] = [1, 2, 3, 4, 5] +strings: String[] = numbers.map { |n| n.to_s } # Result: ["1", "2", "3", "4", "5"] # Map strings to their lengths -words: Array = ["hello", "world", "ruby"] -lengths: Array = words.map { |w| w.length } +words: String[] = ["hello", "world", "ruby"] +lengths: Integer[] = words.map { |w| w.length } # Result: [5, 5, 4] # Map to complex types @@ -88,8 +88,8 @@ class Person end end -names: Array = ["Alice", "Bob"] -people: Array = names.map { |name| Person.new(name, 25) } +names: String[] = ["Alice", "Bob"] +people: Person[] = names.map { |name| Person.new(name, 25) } ``` ### Array Filtering @@ -97,23 +97,23 @@ people: Array = names.map { |name| Person.new(name, 25) } Filtering maintains the same type: ```trb -numbers: Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +numbers: Integer[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # Filter for even numbers -evens: Array = numbers.select { |n| n.even? } +evens: Integer[] = numbers.select { |n| n.even? } # Result: [2, 4, 6, 8, 10] # Filter for odd numbers -odds: Array = numbers.reject { |n| n.even? } +odds: Integer[] = numbers.reject { |n| n.even? } # Result: [1, 3, 5, 7, 9] # Find first matching element -first_even: Integer | nil = numbers.find { |n| n.even? } +first_even: Integer? = numbers.find { |n| n.even? } # Result: 2 # Filter with complex conditions -words: Array = ["hello", "world", "hi", "ruby", "typescript"] -long_words: Array = words.select { |w| w.length > 4 } +words: String[] = ["hello", "world", "hi", "ruby", "typescript"] +long_words: String[] = words.select { |w| w.length > 4 } # Result: ["hello", "world", "typescript"] ``` @@ -122,7 +122,7 @@ long_words: Array = words.select { |w| w.length > 4 } Reduce collapses an array into a single value: ```trb -numbers: Array = [1, 2, 3, 4, 5] +numbers: Integer[] = [1, 2, 3, 4, 5] # Sum all numbers sum: Integer = numbers.reduce(0) { |acc, n| acc + n } @@ -133,12 +133,12 @@ max: Integer = numbers.reduce(numbers[0]) { |max, n| n > max ? n : max } # Result: 5 # Concatenate strings -words: Array = ["Hello", "World", "from", "T-Ruby"] +words: String[] = ["Hello", "World", "from", "T-Ruby"] sentence: String = words.reduce("") { |acc, w| acc.empty? ? w : "#{acc} #{w}" } # Result: "Hello World from T-Ruby" # Build a hash from array -pairs: Array> = [["name", "Alice"], ["age", "30"]] +pairs: String[][] = [["name", "Alice"], ["age", "30"]] hash: Hash = pairs.reduce({}) { |h, pair| h[pair[0]] = pair[1] h @@ -151,25 +151,25 @@ Arrays can be nested to any depth: ```trb # Two-dimensional array (matrix) -matrix: Array> = [ +matrix: Integer[][] = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] # Accessing nested elements -first_row: Array = matrix[0] # [1, 2, 3] -element: Integer | nil = matrix[1][2] # 6 +first_row: Integer[] = matrix[0] # [1, 2, 3] +element: Integer? = matrix[1][2] # 6 # Three-dimensional array -cube: Array>> = [ +cube: Integer[][][] = [ [[1, 2], [3, 4]], [[5, 6], [7, 8]] ] # Flatten nested arrays -nested: Array> = [[1, 2], [3, 4], [5, 6]] -flat: Array = nested.flatten +nested: Integer[][] = [[1, 2], [3, 4], [5, 6]] +flat: Integer[] = nested.flatten # Result: [1, 2, 3, 4, 5, 6] ``` @@ -226,8 +226,8 @@ has_alice: Boolean = ages.key?("Alice") # true has_bob: Boolean = ages.key?("Bob") # false (deleted) # Getting keys and values -keys: Array = ages.keys # ["Alice", "Charlie"] -values: Array = ages.values # [31, 35] +keys: String[] = ages.keys # ["Alice", "Charlie"] +values: Integer[] = ages.values # [31, 35] ``` ### Hash Iteration @@ -245,7 +245,7 @@ scores.each do |name, score| end # Map to arrays -name_score_pairs: Array = scores.map { |name, score| +name_score_pairs: String[] = scores.map { |name, score| "#{name} scored #{score}" } @@ -262,7 +262,7 @@ doubled: Hash = scores.transform_values { |score| score * 2 } ```trb # Hash with array values -tags: Hash> = { +tags: Hash = { "ruby" => ["programming", "language"], "rails" => ["framework", "web"], "postgres" => ["database", "sql"] @@ -326,7 +326,7 @@ intersection: Set = set1 & set2 # {3, 4} difference: Set = set1 - set2 # {1, 2} # Convert to array -array: Array = numbers.to_a +array: Integer[] = numbers.to_a ``` ## Range\ @@ -342,7 +342,7 @@ one_to_nine: Range = 1...10 # Exclusive: 1, 2, ..., 9 includes_five: Boolean = one_to_ten.include?(5) # true # Convert to array -numbers: Array = (1..5).to_a # [1, 2, 3, 4, 5] +numbers: Integer[] = (1..5).to_a # [1, 2, 3, 4, 5] # Iterate over range (1..5).each do |i| @@ -351,7 +351,7 @@ end # Character ranges alphabet: Range = 'a'..'z' -letters: Array = ('a'..'e').to_a # ["a", "b", "c", "d", "e"] +letters: String[] = ('a'..'e').to_a # ["a", "b", "c", "d", "e"] ``` ## Enumerator\ @@ -366,7 +366,7 @@ enum: Enumerator = numbers.each # Lazy evaluation large_range: Enumerator = (1..1_000_000).lazy squares: Enumerator = large_range.map { |n| n * n } -first_five_squares: Array = squares.first(5) +first_five_squares: Integer[] = squares.first(5) # Only computes first 5, not all 1 million # Chain operations lazily @@ -403,7 +403,7 @@ end result = apply_twice(5, doubler) # 20 (5 * 2 * 2) # Array of procs -operations: Array> = [ +operations: Proc[] = [ ->(x: Integer): Integer { x + 1 }, ->(x: Integer): Integer { x * 2 }, ->(x: Integer): Integer { x - 3 } @@ -427,19 +427,19 @@ name: String? = "Alice" age: Integer? = nil # Working with optional arrays -numbers: Array? = [1, 2, 3] +numbers: Integer[]? = [1, 2, 3] numbers = nil # Array of optional elements -numbers: Array = [1, nil, 3, nil, 5] -numbers: Array = [1, nil, 3, nil, 5] # Same as above +numbers: (Integer | nil)[] = [1, nil, 3, nil, 5] +numbers: Integer?[] = [1, nil, 3, nil, 5] # Same as above # Optional hash config: Hash? = { "key" => "value" } config = nil # Hash with optional values -settings: Hash = { +settings: Hash = { "name" => "MyApp", "description" => nil } @@ -451,25 +451,25 @@ Generic types can be combined in powerful ways: ```trb # Array of hashes -users: Array> = [ +users: Hash[] = [ { name: "Alice", age: 30 }, { name: "Bob", age: 25 } ] # Hash of arrays -tags_by_category: Hash> = { +tags_by_category: Hash = { "colors" => ["red", "blue", "green"], "sizes" => ["small", "medium", "large"] } # Array of arrays (matrix) -matrix: Array> = [ +matrix: Integer[][] = [ [1, 2, 3], [4, 5, 6] ] # Hash with complex values -cache: Hash>> = { +cache: Hash[]> = { "users" => [ { id: "1", name: "Alice" }, { id: "2", name: "Bob" } @@ -477,7 +477,7 @@ cache: Hash>> = { } # Optional array of optional values -data: Array? = [1, nil, 3] +data: Integer?[]? = [1, nil, 3] data = nil ``` @@ -487,13 +487,13 @@ Create readable aliases for complex generic types: ```trb # Simple aliases -type StringArray = Array +type StringArray = String[] type IntHash = Hash # Complex aliases type UserData = Hash -type UserList = Array -type TagMap = Hash> +type UserList = UserData[] +type TagMap = Hash # Using aliases users: UserList = [ @@ -523,18 +523,18 @@ T-Ruby's type system understands Ruby's built-in array and hash methods: ```trb # Array methods preserve types -numbers: Array = [1, 2, 3, 4, 5] +numbers: Integer[] = [1, 2, 3, 4, 5] -first_three: Array = numbers.take(3) # [1, 2, 3] -last_two: Array = numbers.drop(3) # [4, 5] -reversed: Array = numbers.reverse # [5, 4, 3, 2, 1] -unique: Array = [1, 2, 2, 3].uniq # [1, 2, 3] -sorted: Array = [3, 1, 2].sort # [1, 2, 3] +first_three: Integer[] = numbers.take(3) # [1, 2, 3] +last_two: Integer[] = numbers.drop(3) # [4, 5] +reversed: Integer[] = numbers.reverse # [5, 4, 3, 2, 1] +unique: Integer[] = [1, 2, 2, 3].uniq # [1, 2, 3] +sorted: Integer[] = [3, 1, 2].sort # [1, 2, 3] # Combining arrays -combined: Array = numbers + [6, 7, 8] # [1, 2, 3, 4, 5, 6, 7, 8] -intersection: Array = [1, 2, 3] & [2, 3, 4] # [2, 3] -difference: Array = [1, 2, 3] - [2, 3] # [1] +combined: Integer[] = numbers + [6, 7, 8] # [1, 2, 3, 4, 5, 6, 7, 8] +intersection: Integer[] = [1, 2, 3] & [2, 3, 4] # [2, 3] +difference: Integer[] = [1, 2, 3] - [2, 3] # [1] # Hash methods hash: Hash = { "a" => 1, "b" => 2 } @@ -551,11 +551,11 @@ counts: Hash = Hash.new(0) counts["a"] += 1 # Safe: default is 0 # Hash with default block -groups: Hash> = Hash.new { |h, k| h[k] = [] } +groups: Hash = Hash.new { |h, k| h[k] = [] } groups["colors"].push("red") # Safe: creates array if missing # Array fetch with default -numbers: Array = [1, 2, 3] +numbers: Integer[] = [1, 2, 3] value: Integer = numbers.fetch(10, 0) # Returns 0 if index out of bounds # Hash fetch with default @@ -569,11 +569,11 @@ port: String = config.fetch("port", "3000") # Returns "3000" if key missing ```trb # Good: Specific types -users: Array = [] +users: User[] = [] config: Hash = {} # Avoid: Using Any loses type safety -data: Array = [] # No type checking +data: Any[] = [] # No type checking ``` ### 2. Use Type Aliases for Complex Types @@ -581,14 +581,14 @@ data: Array = [] # No type checking ```trb # Good: Clear, reusable alias type UserMap = Hash -type ErrorList = Array +type ErrorList = String[] def process_users(users: UserMap): ErrorList # ... end # Less good: Repeated complex types -def process_users(users: Hash): Array +def process_users(users: Hash): String[] # ... end ``` @@ -597,8 +597,8 @@ end ```trb # Good: Explicit nil handling -users: Array = [] -first_user: User | nil = users.first +users: User[] = [] +first_user: User? = users.first if first_user puts first_user.name @@ -617,7 +617,7 @@ end unique_tags: Set = Set.new # Less efficient: Using Array for uniqueness -unique_tags: Array = [] +unique_tags: String[] = [] unique_tags.push(tag) unless unique_tags.include?(tag) ``` @@ -626,7 +626,7 @@ unique_tags.push(tag) unless unique_tags.include?(tag) ### Safe Array Access ```trb -def safe_get(array: Array, index: Integer, default: T): T +def safe_get(array: T[], index: Integer, default: T): T array.fetch(index, default) end @@ -651,14 +651,14 @@ class Person end end -people: Array = [ +people: Person[] = [ Person.new("Alice", 30), Person.new("Bob", 25), Person.new("Charlie", 30) ] # Group by age -by_age: Hash> = people.group_by { |p| p.age } +by_age: Hash = people.group_by { |p| p.age } # { 30 => [Alice, Charlie], 25 => [Bob] } ``` diff --git a/docs/project/changelog.md b/docs/project/changelog.md index 60edfe8..81f90ae 100644 --- a/docs/project/changelog.md +++ b/docs/project/changelog.md @@ -14,6 +14,37 @@ All notable changes to T-Ruby will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.0.43] - 2026-01-10 + +### Added + +#### TypeScript-style Array Shorthand Syntax +- **Array shorthand `T[]`** - Alternative syntax for `Array`, inspired by TypeScript +- **Nested arrays** - `Integer[][]` for `Array>` +- **Nullable arrays** - `String[]?` for `(Array | nil)` +- **Arrays of nullable elements** - `String?[]` for `Array` +- **Union type arrays** - `(String | Integer)[]` for `Array<(String | Integer)>` +- **Full equivalence** - Both `String[]` and `Array` produce identical IR and RBS output + +### Example + +```trb +# Array shorthand syntax +def process(items: String[]): Integer[][] + # items is Array + # returns Array> +end + +# Equivalent to +def process(items: Array): Array> +end + +# Both generate same RBS: +# def process: (items: Array[String]) -> Array[Array[Integer]] +``` + +--- + ## [0.0.39] - 2025-12-24 ### Added @@ -36,14 +67,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Example Before (explicit annotation required): -```ruby +```trb def greet(name: String): String "Hello, #{name}!" end ``` After (inference works automatically): -```ruby +```trb def greet(name: String) "Hello, #{name}!" end @@ -311,6 +342,7 @@ T-Ruby is released under the MIT License. See LICENSE file for details. | Version | Release Date | Status | Highlights | |---------|--------------|--------|------------| +| [0.0.43](#0043---2026-01-10) | 2026-01-10 | Alpha | Array shorthand syntax `T[]` | | [0.0.39](#0039---2025-12-24) | 2025-12-24 | Alpha | TypeScript-style type inference | | [0.1.0-alpha](#010-alpha---2025-12-09) | 2025-12-09 | Alpha | Initial release, core features | | 0.2.0 | TBD | Planned | LSP, tuples, tooling | diff --git a/docs/reference/built-in-types.md b/docs/reference/built-in-types.md index fb2791f..13c7b19 100644 --- a/docs/reference/built-in-types.md +++ b/docs/reference/built-in-types.md @@ -31,7 +31,7 @@ TEXT - `upcase: String` - Converts to uppercase - `downcase: String` - Converts to lowercase - `strip: String` - Removes leading/trailing whitespace -- `split(delimiter: String): Array` - Splits into array +- `split(delimiter: String): String[]` - Splits into array - `include?(substring: String): Boolean` - Checks if contains substring - `empty?: Boolean` - Checks if string is empty @@ -192,43 +192,43 @@ result = Builder.new.append("Hello").append(" ").append("World").build ## Collection Types -### Array\ +### Array\ (or T[]) -Represents an ordered collection of elements of type `T`. +Represents an ordered collection of elements of type `T`. Use shorthand `T[]` or generic `Array`. ```trb # Array of strings -names: Array = ["Alice", "Bob", "Charlie"] +names: String[] = ["Alice", "Bob", "Charlie"] # Array of integers -numbers: Array = [1, 2, 3, 4, 5] +numbers: Integer[] = [1, 2, 3, 4, 5] # Array of mixed types -mixed: Array = ["Alice", 1, "Bob", 2] +mixed: (String | Integer)[] = ["Alice", 1, "Bob", 2] # Nested arrays -matrix: Array> = [[1, 2], [3, 4]] +matrix: Integer[][] = [[1, 2], [3, 4]] # Empty typed array -items: Array = [] +items: String[] = [] ``` **Common Methods:** - `length: Integer` - Returns array length - `size: Integer` - Alias for length - `empty?: Boolean` - Checks if empty -- `first: T | nil` - Returns first element -- `last: T | nil` - Returns last element -- `push(item: T): Array` - Adds element to end -- `pop: T | nil` - Removes and returns last element -- `shift: T | nil` - Removes and returns first element -- `unshift(item: T): Array` - Adds element to beginning +- `first: T?` - Returns first element +- `last: T?` - Returns last element +- `push(item: T): T[]` - Adds element to end +- `pop: T?` - Removes and returns last element +- `shift: T?` - Removes and returns first element +- `unshift(item: T): T[]` - Adds element to beginning - `include?(item: T): Boolean` - Checks if contains element -- `map(&block: Proc): Array` - Transforms elements -- `select(&block: Proc): Array` - Filters elements +- `map(&block: Proc): U[]` - Transforms elements +- `select(&block: Proc): T[]` - Filters elements - `each(&block: Proc): void` - Iterates over elements -- `reverse: Array` - Returns reversed array -- `sort: Array` - Returns sorted array +- `reverse: T[]` - Returns reversed array +- `sort: T[]` - Returns sorted array - `join(separator: String): String` - Joins into string ### Hash\ @@ -260,8 +260,8 @@ cache: Hash = {} - `empty?: Boolean` - Checks if empty - `key?(key: K): Boolean` - Checks if key exists - `value?(value: V): Boolean` - Checks if value exists -- `keys: Array` - Returns array of keys -- `values: Array` - Returns array of values +- `keys: K[]` - Returns array of keys +- `values: V[]` - Returns array of values - `fetch(key: K): V` - Gets value (raises if not found) - `fetch(key: K, default: V): V` - Gets value with default - `merge(other: Hash): Hash` - Merges hashes @@ -285,7 +285,7 @@ unique_ids: Set = Set.new([1, 2, 3, 2, 1]) # {1, 2, 3} - `include?(item: T): Boolean` - Checks membership - `empty?: Boolean` - Checks if empty - `size: Integer` - Returns number of elements -- `to_a: Array` - Converts to array +- `to_a: T[]` - Converts to array ### Range @@ -372,15 +372,15 @@ type Lambda = Proc ```trb # Method accepting a block -def each_item(items: Array, &block: Proc): void +def each_item(items: T[], &block: Proc): void items.each { |item| block.call(item) } end # Block with multiple parameters def map_with_index( - items: Array, + items: T[], &block: Proc -): Array +): U[] items.map.with_index { |item, index| block.call(item, index) } end ``` @@ -497,7 +497,7 @@ end Represents the result of a regular expression match. ```trb -def extract_numbers(text: String): Array | nil +def extract_numbers(text: String): String[]? match: MatchData | nil = text.match(/\d+/) return nil if match.nil? match.to_a @@ -551,7 +551,7 @@ Represents an enumerable object. enum: Enumerator = [1, 2, 3].each range_enum: Enumerator = (1..10).each -def process(enum: Enumerator): Array +def process(enum: Enumerator): T[] enum.to_a end ``` @@ -592,7 +592,7 @@ end | `Boolean` | Primitive | True/false | `true` | | `Symbol` | Primitive | Identifiers | `:active` | | `nil` | Primitive | No value | `nil` | -| `Array` | Collection | Ordered list | `[1, 2, 3]` | +| `T[]` / `Array` | Collection | Ordered list | `[1, 2, 3]` | | `Hash` | Collection | Key-value pairs | `{ "a" => 1 }` | | `Set` | Collection | Unique items | `Set.new([1, 2])` | | `Range` | Collection | Value range | `1..10` | @@ -666,7 +666,7 @@ value.class.name # String ## Best Practices 1. **Use specific types over Any** - `String | Integer` instead of `Any` -2. **Leverage generics for collections** - `Array` instead of `Array` +2. **Leverage generics for collections** - `String[]` or `Array` instead of `Array` 3. **Use union types for optional values** - `String | nil` or `String?` 4. **Choose appropriate collection types** - Use `Set` for uniqueness, `Hash` for lookups 5. **Prefer `void` for side effects** - Clearly indicate functions that don't return values diff --git a/docs/reference/cheatsheet.md b/docs/reference/cheatsheet.md index bc7899c..222821e 100644 --- a/docs/reference/cheatsheet.md +++ b/docs/reference/cheatsheet.md @@ -60,7 +60,7 @@ def greet(name: String, greeting: String = "Hello"): String end # Rest parameters -def sum(*numbers: Array): Integer +def sum(*numbers: Integer[]): Integer numbers.sum end @@ -110,18 +110,22 @@ end ## Array Types ```trb -# Array of specific type -names: Array = ["Alice", "Bob"] -numbers: Array = [1, 2, 3] +# Array of specific type (shorthand syntax) +names: String[] = ["Alice", "Bob"] +numbers: Integer[] = [1, 2, 3] # Array of union types -mixed: Array = ["Alice", 1, "Bob", 2] +mixed: (String | Integer)[] = ["Alice", 1, "Bob", 2] # Nested arrays -matrix: Array> = [[1, 2], [3, 4]] +matrix: Integer[][] = [[1, 2], [3, 4]] # Empty array with type -items: Array = [] +items: String[] = [] + +# Nullable array vs array of nullable +nullable_array: String[]? = nil # The array itself can be nil +array_of_nullable: String?[] = [nil] # Elements can be nil ``` ## Hash Types @@ -146,7 +150,7 @@ users: Hash> = { ```trb # Generic function -def first(arr: Array): T | nil +def first(arr: T[]): T? arr[0] end @@ -185,7 +189,7 @@ type ID = String | Integer type JSONValue = String | Integer | Float | Boolean | nil # Collection alias -type StringList = Array +type StringList = String[] type UserMap = Hash # Generic alias @@ -292,6 +296,7 @@ end | `\|` | Union | Either/or types | `String \| Integer` | | `&` | Intersection | Both types | `Printable & Comparable` | | `?` | Optional | Shorthand for `\| nil` | `String?` | +| `[]` | Array | Array shorthand | `String[]` | | `` | Generic | Type parameter | `Array` | | `=>` | Hash pair | Key-value type | `Hash Integer>` | @@ -307,7 +312,11 @@ end # Optional name: String? # Same as String | nil -# Generics +# Array shorthand +items: String[] +nested: Integer[][] + +# Generics (alternative) items: Array pairs: Hash ``` @@ -316,7 +325,7 @@ pairs: Hash ```trb # Block parameter -def each_item(items: Array, &block: Proc): void +def each_item(items: T[], &block: Proc): void items.each { |item| block.call(item) } end @@ -328,7 +337,7 @@ transformer: Proc = ->(n: Integer): String { n.to_s } double: Proc = ->(n: Integer): Integer { n * 2 } # Block with multiple parameters -def map(items: Array, &block: Proc): Array +def map(items: T[], &block: Proc): U[] items.map.with_index { |item, index| block.call(item, index) } end ``` @@ -481,7 +490,7 @@ end ```trb class QueryBuilder - @conditions: Array + @conditions: String[] def initialize: void @conditions = [] diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/learn/everyday-types/arrays-and-hashes.md b/i18n/ja/docusaurus-plugin-content-docs/current/learn/everyday-types/arrays-and-hashes.md index cc5fa92..8faf0de 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/learn/everyday-types/arrays-and-hashes.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/learn/everyday-types/arrays-and-hashes.md @@ -13,22 +13,22 @@ description: ArrayとHash型の操作 ## Array型 -T-Rubyの配列はジェネリック型構文を使用します:`Array`、ここで`T`は配列の要素の型です。 +T-Rubyの配列は省略構文`T[]`を使用します。ここで`T`は配列の要素の型です。ジェネリック構文`Array`も使用できます。 ### 基本的なArray構文 ```trb title="array_basics.trb" # 整数の配列 -numbers: Array = [1, 2, 3, 4, 5] +numbers: Integer[] = [1, 2, 3, 4, 5] # 文字列の配列 -names: Array = ["Alice", "Bob", "Charlie"] +names: String[] = ["Alice", "Bob", "Charlie"] # 浮動小数点数の配列 -prices: Array = [9.99, 14.99, 19.99] +prices: Float[] = [9.99, 14.99, 19.99] # 空の配列(型アノテーションが必要) -items: Array = [] +items: String[] = [] ``` ### 配列の型推論 @@ -49,25 +49,25 @@ items: Array = [] ### 配列操作 ```trb title="array_operations.trb" -def add_item(items: Array, item: String): Array +def add_item(items: String[], item: String): String[] items << item items end -def get_first(items: Array): String | nil +def get_first(items: String[]): String | nil items.first end -def get_last(items: Array): Integer | nil +def get_last(items: Integer[]): Integer | nil items.last end -def array_length(items: Array): Integer +def array_length(items: String[]): Integer items.length end # 使用法 -list: Array = ["apple", "banana"] +list: String[] = ["apple", "banana"] updated = add_item(list, "cherry") # ["apple", "banana", "cherry"] first: String | nil = get_first(list) # "apple" @@ -77,29 +77,29 @@ count: Integer = array_length(list) # 3 ### 配列要素へのアクセス ```trb title="array_access.trb" -def get_at_index(items: Array, index: Integer): String | nil +def get_at_index(items: String[], index: Integer): String | nil items[index] end -def get_slice(items: Array, start: Integer, length: Integer): Array +def get_slice(items: Integer[], start: Integer, length: Integer): Integer[] items[start, length] end -def get_range(items: Array, range: Range): Array +def get_range(items: String[], range: Range): String[] items[range] end -fruits: Array = ["apple", "banana", "cherry", "date"] +fruits: String[] = ["apple", "banana", "cherry", "date"] item: String | nil = get_at_index(fruits, 0) # "apple" -slice: Array = get_slice([1, 2, 3, 4, 5], 1, 3) # [2, 3, 4] -subset: Array = get_range(fruits, 1..2) # ["banana", "cherry"] +slice: Integer[] = get_slice([1, 2, 3, 4, 5], 1, 3) # [2, 3, 4] +subset: String[] = get_range(fruits, 1..2) # ["banana", "cherry"] ``` ### 配列の反復 ```trb title="array_iteration.trb" -def sum_numbers(numbers: Array): Integer +def sum_numbers(numbers: Integer[]): Integer total = 0 numbers.each do |n| total += n @@ -107,47 +107,47 @@ def sum_numbers(numbers: Array): Integer total end -def double_values(numbers: Array): Array +def double_values(numbers: Integer[]): Integer[] numbers.map { |n| n * 2 } end -def filter_positive(numbers: Array): Array +def filter_positive(numbers: Integer[]): Integer[] numbers.select { |n| n > 0 } end -def find_first_even(numbers: Array): Integer | nil +def find_first_even(numbers: Integer[]): Integer | nil numbers.find { |n| n % 2 == 0 } end total: Integer = sum_numbers([1, 2, 3, 4, 5]) # 15 -doubled: Array = double_values([1, 2, 3]) # [2, 4, 6] -positive: Array = filter_positive([-1, 2, -3, 4]) # [2, 4] +doubled: Integer[] = double_values([1, 2, 3]) # [2, 4, 6] +positive: Integer[] = filter_positive([-1, 2, -3, 4]) # [2, 4] even: Integer | nil = find_first_even([1, 3, 4, 5]) # 4 ``` ### 配列変換メソッド ```trb title="array_transform.trb" -def join_strings(items: Array, separator: String): String +def join_strings(items: String[], separator: String): String items.join(separator) end -def reverse_array(items: Array): Array +def reverse_array(items: Integer[]): Integer[] items.reverse end -def sort_numbers(numbers: Array): Array +def sort_numbers(numbers: Integer[]): Integer[] numbers.sort end -def unique_items(items: Array): Array +def unique_items(items: String[]): String[] items.uniq end joined: String = join_strings(["a", "b", "c"], "-") # "a-b-c" -reversed: Array = reverse_array([1, 2, 3]) # [3, 2, 1] -sorted: Array = sort_numbers([3, 1, 4, 2]) # [1, 2, 3, 4] -unique: Array = unique_items(["a", "b", "a", "c"]) # ["a", "b", "c"] +reversed: Integer[] = reverse_array([1, 2, 3]) # [3, 2, 1] +sorted: Integer[] = sort_numbers([3, 1, 4, 2]) # [1, 2, 3, 4] +unique: String[] = unique_items(["a", "b", "a", "c"]) # ["a", "b", "c"] ``` ### ネストした配列 @@ -156,11 +156,11 @@ unique: Array = unique_items(["a", "b", "a", "c"]) # ["a", "b", "c"] ```trb title="nested_arrays.trb" # 2D配列(配列の配列) -def create_grid(rows: Integer, cols: Integer): Array> - grid: Array> = [] +def create_grid(rows: Integer, cols: Integer): Integer[][] + grid: Integer[][] = [] rows.times do |r| - row: Array = [] + row: Integer[] = [] cols.times do |c| row << (r * cols + c) end @@ -170,12 +170,12 @@ def create_grid(rows: Integer, cols: Integer): Array> grid end -def get_cell(grid: Array>, row: Integer, col: Integer): Integer | nil +def get_cell(grid: Integer[][], row: Integer, col: Integer): Integer | nil return nil if grid[row].nil? grid[row][col] end -matrix: Array> = create_grid(3, 3) +matrix: Integer[][] = create_grid(3, 3) # [[0, 1, 2], [3, 4, 5], [6, 7, 8]] value = get_cell(matrix, 1, 1) # 4 @@ -269,11 +269,11 @@ def print_hash(hash: Hash) end end -def get_keys(hash: Hash): Array +def get_keys(hash: Hash): String[] hash.keys end -def get_values(hash: Hash): Array +def get_values(hash: Hash): Integer[] hash.values end @@ -283,8 +283,8 @@ end scores: Hash = { "alice" => 95, "bob" => 88 } -keys: Array = get_keys(scores) # ["alice", "bob"] -values: Array = get_values({ a: 1, b: 2 }) # [1, 2] +keys: String[] = get_keys(scores) # ["alice", "bob"] +values: Integer[] = get_values({ a: 1, b: 2 }) # [1, 2] doubled: Hash = transform_values({ a: 5, b: 10 }) # { a: 10, b: 20 } @@ -375,11 +375,11 @@ user = create_user("Alice", 30, "alice@example.com") ```trb title="array_unions.trb" # 文字列または整数を含むことができる配列 -def create_mixed_array(): Array +def create_mixed_array(): (String | Integer)[] ["alice", 42, "bob", 100] end -def sum_numbers_from_mixed(items: Array): Integer +def sum_numbers_from_mixed(items: (String | Integer)[]): Integer total = 0 items.each do |item| @@ -391,7 +391,7 @@ def sum_numbers_from_mixed(items: Array): Integer total end -mixed: Array = create_mixed_array() +mixed: (String | Integer)[] = create_mixed_array() sum: Integer = sum_numbers_from_mixed(mixed) # 142 ``` @@ -435,7 +435,7 @@ port: Integer | nil = get_port(config) # 3000 ```trb title="data_processing.trb" class DataProcessor def initialize() - @records: Array> = [] + @records: Hash[] = [] end def add_record(name: String, age: Integer, score: Integer) @@ -447,8 +447,8 @@ class DataProcessor @records << record end - def get_all_names(): Array - names: Array = [] + def get_all_names(): String[] + names: String[] = [] @records.each do |record| name = record[:name] @@ -475,8 +475,8 @@ class DataProcessor total.to_f / @records.length end - def get_top_scorers(threshold: Integer): Array - top_scorers: Array = [] + def get_top_scorers(threshold: Integer): String[] + top_scorers: String[] = [] @records.each do |record| score = record[:score] @@ -490,8 +490,8 @@ class DataProcessor top_scorers end - def group_by_age(): Hash> - groups: Hash> = {} + def group_by_age(): Hash + groups: Hash = {} @records.each do |record| age = record[:age] @@ -535,16 +535,16 @@ processor.add_record("Alice", 25, 95) processor.add_record("Bob", 30, 88) processor.add_record("Charlie", 25, 92) -names: Array = processor.get_all_names() +names: String[] = processor.get_all_names() # ["Alice", "Bob", "Charlie"] avg: Float = processor.get_average_score() # 91.67 -top: Array = processor.get_top_scorers(90) +top: String[] = processor.get_top_scorers(90) # ["Alice", "Charlie"] -by_age: Hash> = processor.group_by_age() +by_age: Hash = processor.group_by_age() # { 25 => ["Alice", "Charlie"], 30 => ["Bob"] } stats: Hash = processor.get_statistics() @@ -556,8 +556,8 @@ stats: Hash = processor.get_statistics() ### 動的に配列を構築 ```trb title="array_building.trb" -def build_range(start: Integer, stop: Integer): Array - result: Array = [] +def build_range(start: Integer, stop: Integer): Integer[] + result: Integer[] = [] i = start while i <= stop @@ -569,10 +569,10 @@ def build_range(start: Integer, stop: Integer): Array end def filter_and_transform( - numbers: Array, + numbers: Integer[], threshold: Integer -): Array - result: Array = [] +): String[] + result: String[] = [] numbers.each do |n| if n > threshold @@ -583,15 +583,15 @@ def filter_and_transform( result end -range: Array = build_range(1, 5) # [1, 2, 3, 4, 5] -filtered: Array = filter_and_transform([10, 5, 20, 3], 8) +range: Integer[] = build_range(1, 5) # [1, 2, 3, 4, 5] +filtered: String[] = filter_and_transform([10, 5, 20, 3], 8) # ["High: 10", "High: 20"] ``` ### 動的にハッシュを構築 ```trb title="hash_building.trb" -def count_occurrences(words: Array): Hash +def count_occurrences(words: String[]): Hash counts: Hash = {} words.each do |word| @@ -607,7 +607,7 @@ def count_occurrences(words: Array): Hash end def index_by_property( - items: Array>, + items: Hash[], key: Symbol ): Hash> index: Hash> = {} @@ -622,7 +622,7 @@ def index_by_property( index end -words: Array = ["apple", "banana", "apple", "cherry", "banana", "apple"] +words: String[] = ["apple", "banana", "apple", "cherry", "banana", "apple"] counts: Hash = count_occurrences(words) # { "apple" => 3, "banana" => 2, "cherry" => 1 } ``` @@ -636,31 +636,31 @@ counts: Hash = count_occurrences(words) # items = [] # エラー! # 常に空のコレクションにアノテーションを付ける -items: Array = [] +items: String[] = [] config: Hash = {} ``` ### コレクションの変更 ```trb title="mutation.trb" -def add_item_wrong(items: Array): Array +def add_item_wrong(items: String[]): String[] # これは元の配列を変更する items << "new" items end -def add_item_safe(items: Array): Array +def add_item_safe(items: String[]): String[] # 最初にコピーを作成 new_items = items.dup new_items << "new" new_items end -original: Array = ["a", "b"] +original: String[] = ["a", "b"] result1 = add_item_wrong(original) # originalは今["a", "b", "new"]! -original2: Array = ["a", "b"] +original2: String[] = ["a", "b"] result2 = add_item_safe(original2) # original2はまだ["a", "b"] ``` @@ -685,7 +685,7 @@ end 配列とハッシュはT-Rubyの必須コレクション型です: -- **配列**は同種のコレクションに`Array`構文を使用 +- **配列**は同種のコレクションに`T[]`省略構文を使用(または`Array`) - **ハッシュ**はキーと値のペアに`Hash`構文を使用 - **型推論**は空でないコレクションで機能 - **空のコレクション**は常に型アノテーションが必要 diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/learn/functions/optional-rest-parameters.md b/i18n/ja/docusaurus-plugin-content-docs/current/learn/functions/optional-rest-parameters.md index a5f6503..57b18ca 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/learn/functions/optional-rest-parameters.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/learn/functions/optional-rest-parameters.md @@ -68,15 +68,15 @@ send_email("bob@example.com", "Meeting", "team@example.com") 残余パラメータは複数の引数を配列に収集します。配列の要素型を指定します: ```trb title="rest.trb" -def sum(*numbers: Array): Integer +def sum(*numbers: Integer[]): Integer numbers.reduce(0, :+) end -def concat_strings(*strings: Array): String +def concat_strings(*strings: String[]): String strings.join(" ") end -def log_messages(level: String, *messages: Array): void +def log_messages(level: String, *messages: String[]): void messages.each do |msg| puts "[#{level}] #{msg}" end @@ -96,7 +96,7 @@ log_messages("INFO", "App started", "Database connected", "Ready") # [INFO] Ready ``` -型アノテーション `*numbers: Array` は「配列に収集される0個以上のInteger引数」を意味します。 +型アノテーション `*numbers: Integer[]` は「配列に収集される0個以上のInteger引数」を意味します。 ## オプショナルパラメータと残余パラメータの組み合わせ @@ -107,7 +107,7 @@ def create_team( name: String, leader: String, active: Boolean = true, - *members: Array + *members: String[] ): Team Team.new( name: name, @@ -155,7 +155,7 @@ def create_post({ title: String, content: String, published: Boolean = false, - tags: Array = [] + tags: String[] = [] }): Post Post.new( title: title, @@ -292,7 +292,7 @@ user2 = register_user( def complex_function( required_pos: String, # 1. 必須位置 optional_pos: Integer = 0, # 2. オプショナル位置 - *rest_args: Array, # 3. 残余パラメータ + *rest_args: String[], # 3. 残余パラメータ { required_kw: Boolean, # 4. 必須キーワード optional_kw: String = "default" # 5. オプショナルキーワード @@ -339,7 +339,7 @@ class HTTPRequestBuilder end # 必須 + 残余パラメータ - def delete(*urls: Array): Array + def delete(*urls: String[]): Response[] urls.map { |url| make_request("DELETE", url, nil, {}) } end @@ -429,7 +429,7 @@ class Logger end # 残余パラメータで複数メッセージ - def log_many(level: String, *messages: Array): void + def log_many(level: String, *messages: String[]): void messages.each { |msg| log(msg, level) } end @@ -440,7 +440,7 @@ class Logger end # 柔軟なデバッグロギング - def debug(*messages: Array, **context: Hash): void + def debug(*messages: String[], **context: Hash): void messages.each do |msg| ctx_str = context.empty? ? "" : " (#{context.map { |k, v| "#{k}=#{v}" }.join(", ")})" puts "[DEBUG] #{msg}#{ctx_str}" @@ -500,8 +500,8 @@ def build_email({ subject: String, from: String = "noreply@example.com", reply_to: String? = nil, - cc: Array = [], - bcc: Array = [] + cc: String[] = [], + bcc: String[] = [] }): Email Email.new(to, subject, from, reply_to, cc, bcc) end @@ -513,7 +513,7 @@ email = build_email(to: "alice@example.com", subject: "Hello") ### 可変ファクトリ関数(残余 + キーワード引数) ```trb title="factory.trb" -def create_users(*names: Array, { role: String = "user" }): Array +def create_users(*names: String[], { role: String = "user" }): User[] names.map { |name| User.new(name: name, role: role) } end @@ -542,7 +542,7 @@ config = merge_config( |------|------|----------| | `(x: Type)` | 位置引数 | `foo("hi")` | | `(x: Type = default)` | オプショナル位置引数 | `foo()` または `foo("hi")` | -| `(*args: Array)` | 残余パラメータ | `foo("a", "b", "c")` | +| `(*args: Type[])` | 残余パラメータ | `foo("a", "b", "c")` | | `({ x: Type })` | キーワード引数 | `foo(x: "hi")` | | `(config: { x: Type })` | Hashリテラル | `foo(config: { x: "hi" })` | | `(**kwargs: Hash)` | キーワード残余 | `foo(a: 1, b: 2)` | diff --git a/i18n/ja/docusaurus-plugin-content-docs/current/project/changelog.md b/i18n/ja/docusaurus-plugin-content-docs/current/project/changelog.md index 0e0bf1d..d0fdf86 100644 --- a/i18n/ja/docusaurus-plugin-content-docs/current/project/changelog.md +++ b/i18n/ja/docusaurus-plugin-content-docs/current/project/changelog.md @@ -36,14 +36,14 @@ T-Rubyのすべての注目すべき変更はこのファイルに文書化さ ### 例 以前(明示的なアノテーションが必要): -```ruby +```trb def greet(name: String): String "Hello, #{name}!" end ``` 以後(推論が自動的に動作): -```ruby +```trb def greet(name: String) "Hello, #{name}!" end diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/learn/everyday-types/arrays-and-hashes.md b/i18n/ko/docusaurus-plugin-content-docs/current/learn/everyday-types/arrays-and-hashes.md index 6629669..6d24616 100644 --- a/i18n/ko/docusaurus-plugin-content-docs/current/learn/everyday-types/arrays-and-hashes.md +++ b/i18n/ko/docusaurus-plugin-content-docs/current/learn/everyday-types/arrays-and-hashes.md @@ -13,7 +13,7 @@ description: Array와 Hash 타입 다루기 ## Array 타입 -T-Ruby의 배열은 제네릭 타입 구문을 사용합니다: `Array`, 여기서 `T`는 배열의 요소 타입입니다. +T-Ruby의 배열은 축약 구문 `T[]`를 사용합니다. 여기서 `T`는 배열의 요소 타입입니다. 제네릭 구문 `Array`도 사용 가능합니다. ### 기본 Array 구문 @@ -21,16 +21,16 @@ T-Ruby의 배열은 제네릭 타입 구문을 사용합니다: `Array`, 여 ```trb title="array_basics.trb" # 정수 배열 -numbers: Array = [1, 2, 3, 4, 5] +numbers: Integer[] = [1, 2, 3, 4, 5] # 문자열 배열 -names: Array = ["Alice", "Bob", "Charlie"] +names: String[] = ["Alice", "Bob", "Charlie"] # 실수 배열 -prices: Array = [9.99, 14.99, 19.99] +prices: Float[] = [9.99, 14.99, 19.99] # 빈 배열 (타입 어노테이션 필요) -items: Array = [] +items: String[] = [] ``` ### 배열의 타입 추론 @@ -55,25 +55,25 @@ items: Array = [] ```trb title="array_operations.trb" -def add_item(items: Array, item: String): Array +def add_item(items: String[], item: String): String[] items << item items end -def get_first(items: Array): String | nil +def get_first(items: String[]): String | nil items.first end -def get_last(items: Array): Integer | nil +def get_last(items: Integer[]): Integer | nil items.last end -def array_length(items: Array): Integer +def array_length(items: String[]): Integer items.length end # 사용법 -list: Array = ["apple", "banana"] +list: String[] = ["apple", "banana"] updated = add_item(list, "cherry") # ["apple", "banana", "cherry"] first: String | nil = get_first(list) # "apple" @@ -85,23 +85,23 @@ count: Integer = array_length(list) # 3 ```trb title="array_access.trb" -def get_at_index(items: Array, index: Integer): String | nil +def get_at_index(items: String[], index: Integer): String | nil items[index] end -def get_slice(items: Array, start: Integer, length: Integer): Array +def get_slice(items: Integer[], start: Integer, length: Integer): Integer[] items[start, length] end -def get_range(items: Array, range: Range): Array +def get_range(items: String[], range: Range): String[] items[range] end -fruits: Array = ["apple", "banana", "cherry", "date"] +fruits: String[] = ["apple", "banana", "cherry", "date"] item: String | nil = get_at_index(fruits, 0) # "apple" -slice: Array = get_slice([1, 2, 3, 4, 5], 1, 3) # [2, 3, 4] -subset: Array = get_range(fruits, 1..2) # ["banana", "cherry"] +slice: Integer[] = get_slice([1, 2, 3, 4, 5], 1, 3) # [2, 3, 4] +subset: String[] = get_range(fruits, 1..2) # ["banana", "cherry"] ``` ### 배열 반복 @@ -109,7 +109,7 @@ subset: Array = get_range(fruits, 1..2) # ["banana", "cherry"] ```trb title="array_iteration.trb" -def sum_numbers(numbers: Array): Integer +def sum_numbers(numbers: Integer[]): Integer total = 0 numbers.each do |n| total += n @@ -117,21 +117,21 @@ def sum_numbers(numbers: Array): Integer total end -def double_values(numbers: Array): Array +def double_values(numbers: Integer[]): Integer[] numbers.map { |n| n * 2 } end -def filter_positive(numbers: Array): Array +def filter_positive(numbers: Integer[]): Integer[] numbers.select { |n| n > 0 } end -def find_first_even(numbers: Array): Integer | nil +def find_first_even(numbers: Integer[]): Integer | nil numbers.find { |n| n % 2 == 0 } end total: Integer = sum_numbers([1, 2, 3, 4, 5]) # 15 -doubled: Array = double_values([1, 2, 3]) # [2, 4, 6] -positive: Array = filter_positive([-1, 2, -3, 4]) # [2, 4] +doubled: Integer[] = double_values([1, 2, 3]) # [2, 4, 6] +positive: Integer[] = filter_positive([-1, 2, -3, 4]) # [2, 4] even: Integer | nil = find_first_even([1, 3, 4, 5]) # 4 ``` @@ -140,26 +140,26 @@ even: Integer | nil = find_first_even([1, 3, 4, 5]) # 4 ```trb title="array_transform.trb" -def join_strings(items: Array, separator: String): String +def join_strings(items: String[], separator: String): String items.join(separator) end -def reverse_array(items: Array): Array +def reverse_array(items: Integer[]): Integer[] items.reverse end -def sort_numbers(numbers: Array): Array +def sort_numbers(numbers: Integer[]): Integer[] numbers.sort end -def unique_items(items: Array): Array +def unique_items(items: String[]): String[] items.uniq end joined: String = join_strings(["a", "b", "c"], "-") # "a-b-c" -reversed: Array = reverse_array([1, 2, 3]) # [3, 2, 1] -sorted: Array = sort_numbers([3, 1, 4, 2]) # [1, 2, 3, 4] -unique: Array = unique_items(["a", "b", "a", "c"]) # ["a", "b", "c"] +reversed: Integer[] = reverse_array([1, 2, 3]) # [3, 2, 1] +sorted: Integer[] = sort_numbers([3, 1, 4, 2]) # [1, 2, 3, 4] +unique: String[] = unique_items(["a", "b", "a", "c"]) # ["a", "b", "c"] ``` ### 중첩 배열 @@ -170,11 +170,11 @@ unique: Array = unique_items(["a", "b", "a", "c"]) # ["a", "b", "c"] ```trb title="nested_arrays.trb" # 2D 배열 (배열의 배열) -def create_grid(rows: Integer, cols: Integer): Array> - grid: Array> = [] +def create_grid(rows: Integer, cols: Integer): Integer[][] + grid: Integer[][] = [] rows.times do |r| - row: Array = [] + row: Integer[] = [] cols.times do |c| row << (r * cols + c) end @@ -184,12 +184,12 @@ def create_grid(rows: Integer, cols: Integer): Array> grid end -def get_cell(grid: Array>, row: Integer, col: Integer): Integer | nil +def get_cell(grid: Integer[][], row: Integer, col: Integer): Integer | nil return nil if grid[row].nil? grid[row][col] end -matrix: Array> = create_grid(3, 3) +matrix: Integer[][] = create_grid(3, 3) # [[0, 1, 2], [3, 4, 5], [6, 7, 8]] value = get_cell(matrix, 1, 1) # 4 @@ -291,11 +291,11 @@ def print_hash(hash: Hash) end end -def get_keys(hash: Hash): Array +def get_keys(hash: Hash): String[] hash.keys end -def get_values(hash: Hash): Array +def get_values(hash: Hash): Integer[] hash.values end @@ -305,8 +305,8 @@ end scores: Hash = { "alice" => 95, "bob" => 88 } -keys: Array = get_keys(scores) # ["alice", "bob"] -values: Array = get_values({ a: 1, b: 2 }) # [1, 2] +keys: String[] = get_keys(scores) # ["alice", "bob"] +values: Integer[] = get_values({ a: 1, b: 2 }) # [1, 2] doubled: Hash = transform_values({ a: 5, b: 10 }) # { a: 10, b: 20 } @@ -403,11 +403,11 @@ user = create_user("Alice", 30, "alice@example.com") ```trb title="array_unions.trb" # 문자열 또는 정수를 포함할 수 있는 배열 -def create_mixed_array(): Array +def create_mixed_array(): (String | Integer)[] ["alice", 42, "bob", 100] end -def sum_numbers_from_mixed(items: Array): Integer +def sum_numbers_from_mixed(items: (String | Integer)[]): Integer total = 0 items.each do |item| @@ -419,7 +419,7 @@ def sum_numbers_from_mixed(items: Array): Integer total end -mixed: Array = create_mixed_array() +mixed: (String | Integer)[] = create_mixed_array() sum: Integer = sum_numbers_from_mixed(mixed) # 142 ``` @@ -467,7 +467,7 @@ port: Integer | nil = get_port(config) # 3000 ```trb title="data_processing.trb" class DataProcessor def initialize() - @records: Array> = [] + @records: Hash[] = [] end def add_record(name: String, age: Integer, score: Integer) @@ -479,8 +479,8 @@ class DataProcessor @records << record end - def get_all_names(): Array - names: Array = [] + def get_all_names(): String[] + names: String[] = [] @records.each do |record| name = record[:name] @@ -507,8 +507,8 @@ class DataProcessor total.to_f / @records.length end - def get_top_scorers(threshold: Integer): Array - top_scorers: Array = [] + def get_top_scorers(threshold: Integer): String[] + top_scorers: String[] = [] @records.each do |record| score = record[:score] @@ -522,8 +522,8 @@ class DataProcessor top_scorers end - def group_by_age(): Hash> - groups: Hash> = {} + def group_by_age(): Hash + groups: Hash = {} @records.each do |record| age = record[:age] @@ -567,16 +567,16 @@ processor.add_record("Alice", 25, 95) processor.add_record("Bob", 30, 88) processor.add_record("Charlie", 25, 92) -names: Array = processor.get_all_names() +names: String[] = processor.get_all_names() # ["Alice", "Bob", "Charlie"] avg: Float = processor.get_average_score() # 91.67 -top: Array = processor.get_top_scorers(90) +top: String[] = processor.get_top_scorers(90) # ["Alice", "Charlie"] -by_age: Hash> = processor.group_by_age() +by_age: Hash = processor.group_by_age() # { 25 => ["Alice", "Charlie"], 30 => ["Bob"] } stats: Hash = processor.get_statistics() @@ -590,8 +590,8 @@ stats: Hash = processor.get_statistics() ```trb title="array_building.trb" -def build_range(start: Integer, stop: Integer): Array - result: Array = [] +def build_range(start: Integer, stop: Integer): Integer[] + result: Integer[] = [] i = start while i <= stop @@ -603,10 +603,10 @@ def build_range(start: Integer, stop: Integer): Array end def filter_and_transform( - numbers: Array, + numbers: Integer[], threshold: Integer -): Array - result: Array = [] +): String[] + result: String[] = [] numbers.each do |n| if n > threshold @@ -617,8 +617,8 @@ def filter_and_transform( result end -range: Array = build_range(1, 5) # [1, 2, 3, 4, 5] -filtered: Array = filter_and_transform([10, 5, 20, 3], 8) +range: Integer[] = build_range(1, 5) # [1, 2, 3, 4, 5] +filtered: String[] = filter_and_transform([10, 5, 20, 3], 8) # ["High: 10", "High: 20"] ``` @@ -627,7 +627,7 @@ filtered: Array = filter_and_transform([10, 5, 20, 3], 8) ```trb title="hash_building.trb" -def count_occurrences(words: Array): Hash +def count_occurrences(words: String[]): Hash counts: Hash = {} words.each do |word| @@ -643,7 +643,7 @@ def count_occurrences(words: Array): Hash end def index_by_property( - items: Array>, + items: Hash[], key: Symbol ): Hash> index: Hash> = {} @@ -658,7 +658,7 @@ def index_by_property( index end -words: Array = ["apple", "banana", "apple", "cherry", "banana", "apple"] +words: String[] = ["apple", "banana", "apple", "cherry", "banana", "apple"] counts: Hash = count_occurrences(words) # { "apple" => 3, "banana" => 2, "cherry" => 1 } ``` @@ -674,7 +674,7 @@ counts: Hash = count_occurrences(words) # items = [] # 오류! # 항상 빈 컬렉션에 어노테이션 추가 -items: Array = [] +items: String[] = [] config: Hash = {} ``` @@ -683,24 +683,24 @@ config: Hash = {} ```trb title="mutation.trb" -def add_item_wrong(items: Array): Array +def add_item_wrong(items: String[]): String[] # 이것은 원본 배열을 변경함 items << "new" items end -def add_item_safe(items: Array): Array +def add_item_safe(items: String[]): String[] # 먼저 복사본 생성 new_items = items.dup new_items << "new" new_items end -original: Array = ["a", "b"] +original: String[] = ["a", "b"] result1 = add_item_wrong(original) # original이 이제 ["a", "b", "new"]! -original2: Array = ["a", "b"] +original2: String[] = ["a", "b"] result2 = add_item_safe(original2) # original2는 여전히 ["a", "b"] ``` @@ -727,7 +727,7 @@ end 배열과 해시는 T-Ruby의 필수 컬렉션 타입입니다: -- **배열**은 동종 컬렉션에 `Array` 구문 사용 +- **배열**은 동종 컬렉션에 `T[]` 축약 구문 사용 (또는 `Array`) - **해시**는 키-값 쌍에 `Hash` 구문 사용 - **타입 추론**은 비어있지 않은 컬렉션에서 작동 - **빈 컬렉션**은 항상 타입 어노테이션 필요 diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/learn/functions/optional-rest-parameters.md b/i18n/ko/docusaurus-plugin-content-docs/current/learn/functions/optional-rest-parameters.md index 2c3e5ee..a274ae4 100644 --- a/i18n/ko/docusaurus-plugin-content-docs/current/learn/functions/optional-rest-parameters.md +++ b/i18n/ko/docusaurus-plugin-content-docs/current/learn/functions/optional-rest-parameters.md @@ -74,15 +74,15 @@ send_email("bob@example.com", "Meeting", "team@example.com") ```trb title="rest.trb" -def sum(*numbers: Array): Integer +def sum(*numbers: Integer[]): Integer numbers.reduce(0, :+) end -def concat_strings(*strings: Array): String +def concat_strings(*strings: String[]): String strings.join(" ") end -def log_messages(level: String, *messages: Array): void +def log_messages(level: String, *messages: String[]): void messages.each do |msg| puts "[#{level}] #{msg}" end @@ -102,7 +102,7 @@ log_messages("INFO", "App started", "Database connected", "Ready") # [INFO] Ready ``` -타입 어노테이션 `*numbers: Array`는 "배열로 수집되는 0개 이상의 Integer 인수"를 의미합니다. +타입 어노테이션 `*numbers: Integer[]`는 "배열로 수집되는 0개 이상의 Integer 인수"를 의미합니다. ## 선택적 매개변수와 나머지 매개변수 조합 @@ -115,7 +115,7 @@ def create_team( name: String, leader: String, active: Boolean = true, - *members: Array + *members: String[] ): Team Team.new( name: name, @@ -166,7 +166,7 @@ def create_post({ title: String, content: String, published: Boolean = false, - tags: Array = [] + tags: String[] = [] }): Post Post.new( title: title, @@ -311,7 +311,7 @@ user2 = register_user( def complex_function( required_pos: String, # 1. 필수 위치 optional_pos: Integer = 0, # 2. 선택적 위치 - *rest_args: Array, # 3. 나머지 매개변수 + *rest_args: String[], # 3. 나머지 매개변수 { required_kw: Boolean, # 4. 필수 키워드 optional_kw: String = "default" # 5. 선택적 키워드 @@ -361,7 +361,7 @@ class HTTPRequestBuilder end # 나머지 매개변수 - def delete(*urls: Array): Array + def delete(*urls: String[]): Response[] urls.map { |url| make_request("DELETE", url, nil, {}) } end @@ -454,7 +454,7 @@ class Logger end # 나머지 매개변수로 여러 메시지 - def log_many(level: String, *messages: Array): void + def log_many(level: String, *messages: String[]): void messages.each { |msg| log(msg, level) } end @@ -465,7 +465,7 @@ class Logger end # 나머지 매개변수 + 키워드 나머지 - def debug(*messages: Array, **context: Hash): void + def debug(*messages: String[], **context: Hash): void messages.each do |msg| ctx_str = context.empty? ? "" : " (#{context.map { |k, v| "#{k}=#{v}" }.join(", ")})" puts "[DEBUG] #{msg}#{ctx_str}" @@ -528,8 +528,8 @@ def build_email({ subject: String, from: String = "noreply@example.com", reply_to: String? = nil, - cc: Array = [], - bcc: Array = [] + cc: String[] = [], + bcc: String[] = [] }): Email Email.new(to, subject, from, reply_to, cc, bcc) end @@ -544,7 +544,7 @@ email = build_email(to: "alice@example.com", subject: "Hello") {/* */} ```trb title="factory.trb" -def create_users(*names: Array, { role: String = "user" }): Array +def create_users(*names: String[], { role: String = "user" }): User[] names.map { |name| User.new(name: name, role: role) } end @@ -576,7 +576,7 @@ config = merge_config( |------|------|----------| | `(x: Type)` | 위치 인수 | `foo("hi")` | | `(x: Type = default)` | 선택적 위치 인수 | `foo()` 또는 `foo("hi")` | -| `(*args: Array)` | 나머지 매개변수 | `foo("a", "b", "c")` | +| `(*args: Type[])` | 나머지 매개변수 | `foo("a", "b", "c")` | | `({ x: Type })` | 키워드 인수 | `foo(x: "hi")` | | `(config: { x: Type })` | Hash 리터럴 | `foo(config: { x: "hi" })` | | `(**kwargs: Hash)` | 키워드 나머지 | `foo(a: 1, b: 2)` | diff --git a/i18n/ko/docusaurus-plugin-content-docs/current/project/changelog.md b/i18n/ko/docusaurus-plugin-content-docs/current/project/changelog.md index 8a07141..168e1c8 100644 --- a/i18n/ko/docusaurus-plugin-content-docs/current/project/changelog.md +++ b/i18n/ko/docusaurus-plugin-content-docs/current/project/changelog.md @@ -36,14 +36,14 @@ T-Ruby의 모든 주목할 만한 변경 사항은 이 파일에 문서화됩니 ### 예제 이전 (명시적 어노테이션 필요): -```ruby +```trb def greet(name: String): String "Hello, #{name}!" end ``` 이후 (추론이 자동으로 동작): -```ruby +```trb def greet(name: String) "Hello, #{name}!" end