Callable 与 lambda

六个操作以 Callable 的形式存在数组里,五个 lambda 加一个用 bind 的方法,每个都交给 Array.map 处理同一组数字。

上方的编辑器正在运行这个项目。改一行代码,它就会重新加载。

用到的 Godot 类

CallableCallable.bindArray.map

代码

scripts/main.gd
extends Node

const SOURCE: Array = [3, 8, 1, 6, 9, 4, 7, 2]
const TICK: float = 0.45

var operations: Array = []
var rows: Array = []
var buttons: Array = []
var status: Label
var elapsed: float = 0.0
var active: int = 0


func _ready() -> void:
	operations = [
		{name = 'double', fn = func(value: int) -> int: return value * 2},
		{name = 'square', fn = func(value: int) -> int: return value * value},
		{name = 'halve', fn = func(value: int) -> int: return roundi(value * 0.5)},
		{name = 'mirror', fn = func(value: int) -> int: return 10 - value},
		{name = 'cap at five', fn = func(value: int) -> int: return mini(value, 5)},
		{name = 'add bonus, bound', fn = _add_bonus.bind(12)},
	]

	var row: HBoxContainer = _root()
	_menu(row)
	_table(row)
	_apply(0)

	print('every entry in the list is a Callable, five lambdas and one method with bind')


func _process(delta: float) -> void:
	elapsed += delta

	if elapsed < TICK:
		return

	elapsed = 0.0
	_apply((active + 1) % operations.size())


func _add_bonus(value: int, bonus: int) -> int:
	return value + bonus


func _apply(index: int) -> void:
	active = index
	var operation: Dictionary = operations[index]
	var result: Array = SOURCE.map(operation.fn)
	var ceiling: int = maxi(int(result.max()), 1)

	for i in SOURCE.size():
		var line: Dictionary = rows[i]
		line.result.text = str(result[i])
		line.bar.max_value = ceiling
		line.bar.value = result[i]

	for i in buttons.size():
		buttons[i].add_theme_color_override('font_color', Color('#8eef97') if i == index else Color('#8a90a0'))

	status.text = 'SOURCE.map(operations[%d].fn) gave %s' % [index, str(result)]


func _menu(row: HBoxContainer) -> void:
	var column: VBoxContainer = VBoxContainer.new()
	column.custom_minimum_size = Vector2(300, 0)
	column.add_theme_constant_override('separation', 8)
	row.add_child(column)

	var title: Label = Label.new()
	title.text = 'the list of Callables'
	title.add_theme_font_size_override('font_size', 22)
	title.add_theme_color_override('font_color', Color('#8da5f3'))
	column.add_child(title)

	for i in operations.size():
		var button: Button = Button.new()
		button.text = operations[i].name
		button.pressed.connect(_apply.bind(i))
		column.add_child(button)
		buttons.append(button)


func _table(row: HBoxContainer) -> void:
	var column: VBoxContainer = VBoxContainer.new()
	column.custom_minimum_size = Vector2(660, 0)
	column.add_theme_constant_override('separation', 8)
	row.add_child(column)

	var title: Label = Label.new()
	title.text = 'the same eight numbers, mapped'
	title.add_theme_font_size_override('font_size', 22)
	title.add_theme_color_override('font_color', Color('#8eef97'))
	column.add_child(title)

	for value in SOURCE:
		var line: HBoxContainer = HBoxContainer.new()
		line.add_theme_constant_override('separation', 14)
		column.add_child(line)

		var source: Label = Label.new()
		source.text = str(value)
		source.custom_minimum_size = Vector2(34, 0)
		source.add_theme_color_override('font_color', Color('#8a90a0'))
		line.add_child(source)

		var arrow: Label = Label.new()
		arrow.text = '->'
		arrow.add_theme_color_override('font_color', Color('#8a90a0'))
		line.add_child(arrow)

		var result: Label = Label.new()
		result.custom_minimum_size = Vector2(48, 0)
		result.add_theme_font_size_override('font_size', 20)
		line.add_child(result)

		var bar: ProgressBar = ProgressBar.new()
		bar.show_percentage = false
		bar.custom_minimum_size = Vector2(440, 18)
		bar.add_theme_stylebox_override('background', _bar_style(Color('#2a2f3d')))
		bar.add_theme_stylebox_override('fill', _bar_style(Color('#8da5f3')))
		line.add_child(bar)

		rows.append({result = result, bar = bar})


func _bar_style(color: Color) -> StyleBoxFlat:
	var style: StyleBoxFlat = StyleBoxFlat.new()
	style.bg_color = color
	style.set_corner_radius_all(5)

	return style


func _root() -> HBoxContainer:
	var background: ColorRect = ColorRect.new()
	background.color = Color('#12141a')
	add_child(background)
	background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)

	var margin: MarginContainer = MarginContainer.new()

	for side in ['margin_left', 'margin_right', 'margin_top', 'margin_bottom']:
		margin.add_theme_constant_override(side, 48)

	add_child(margin)
	margin.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)

	var column: VBoxContainer = VBoxContainer.new()
	column.add_theme_constant_override('separation', 16)
	margin.add_child(column)

	var title: Label = Label.new()
	title.text = 'A function kept in a variable'
	title.add_theme_font_size_override('font_size', 28)
	column.add_child(title)

	var hint: Label = Label.new()
	hint.text = 'Nothing below knows what the operation is. It receives a Callable and hands it to Array.map.'
	hint.add_theme_color_override('font_color', Color('#8a90a0'))
	column.add_child(hint)

	var row: HBoxContainer = HBoxContainer.new()
	row.add_theme_constant_override('separation', 36)
	column.add_child(row)

	status = Label.new()
	status.add_theme_font_size_override('font_size', 18)
	status.add_theme_color_override('font_color', Color('#8eef97'))
	column.add_child(status)

	return row

更多数据示例