URBI - введение в urbiScript - часть 3

1. введение в urbiScript — часть 1
2. введение в urbiScript — часть 2
3. введение в urbiScript — часть 3

Продолжаем рассмотрение возможностей скриптового языка urbiScript от компании Gostai, предназначенного для управления роботами.

Напомню, что urbiScript выполняется на Urbi-сервере, который запускается либо на роботе, либо на компьютере и к которому можно подключиться через сеть обычным telnet-ом.

16. Прототипное программирование в urbiScript

Для примера рассмотрим объект Pair — контейнер, который содержит две величины (first и second) и похож н std::pair в С++.

Pair;
[00000000] (nil, nil)


Видим, что Pair содержит две переменных, которые равны nil (по-умолчанию).
Клонируем Pair в свою переменную:

var p = Pair.clone;
[00000000] (nil, nil)
p.first = "101010";
[00000000] "101010"
p.second = true;
[00000000] true
p;
[00000000] ("101010", true)
Pair;
[00000000] (nil, nil)


Т.к. Pair — это объект, то можно модифицировать его свойства. Но это отнюдь не лучшая идея, т.к. новые свойства будут изменять не только следующих производных от Pair, но и предыдущих:

var before = Pair.clone;
[00000000] (nil, nil)
Pair.first = false;
[00000000] false
var after = Pair.clone;
[00000000] (false, nil)
before;
[00000000] (false, nil)
// before и after имеют доступ к тому же значению first.
assert(Pair.first === before.first);
assert(Pair.first === after.first);


17. Псевдоклассы

Например, для определения своего класса Pair нужно создать объект с двумя слотами first и second (первый и второй).
Для этого можно использовать ключевое слово do

var MyPair = Object.clone;
[00000000] Object_0x1
do (MyPair)
{
	var first = nil;
	var second = nil;
	function asString ()
	{
	"MyPair: " + first + ", " + second
	};
} | {};
// создали свой объект Pair
MyPair;
[00000000] MyPair: nil, nil
// испытаем
var p = MyPair.clone;
[00000000] MyPair: nil, nil
p.first = 0;
[00000000] 0
p;
[00000000] MyPair: 0, nil
MyPair;
[00000000] MyPair: nil, nil


то же самое можно проделать используя ключевое слово class:

class MyPair
{
	var first = nil;
	var second = nil;
	function asString() { "(" + first + ", " + second + ")"; };
};
[00000000] (nil, nil)


Т.е. ключевое слово class просто создаёт объект MyPair, клонируя Object и предоставляет оболочку do.

18. Конструктор
Некоторые классы поддерживают конструкторы, доступные через метод new (вместо метода clone), принимающего передаваемые параметры.

var p = Pair.new("foo", false);
[00000000] ("foo", false) 


Т.о. получается, что clone гарантирует получение пустого объекта, наследуемого от прототипа.
метод new по-умолчанию делает то же самое, но позволяет сразу задавать новые атрибуты объекта.

Для определения конструктора, прототипу достаточно иметь функцию init, которая будет вызвана с параметрами, переданными методу new.
Добавим конструктор классу MyPair из предыдущего примера:

class MyPair
{
	var first = nil;
	var second = nil;
	function init(f, s) { first = f; second = s; };
	function asString() { "(" + first + ", " + second + ")"; };
};
[00000000] (nil, nil)
MyPair.new(0, 1);
[00000000] (0, 1)


19. Операторы

urbiScript поддерживает перегрузку операторов.

class ArithPair
{
	var first = nil;
	var second = nil;
	function init(f, s) { first = f; second = s; };
	function asString() { "(" + first + ", " + second + ")"; };
	function '+'(rhs) { new(first + rhs.first, second + rhs.second); };
	function '-'(rhs) { new(first - rhs.first, second - rhs.second); };
	function '*'(rhs) { new(first * rhs.first, second * rhs.second); };
	function '/'(rhs) { new(first / rhs.first, second / rhs.second); };
};
[00000000] (nil, nil)
ArithPair.new(1, 10) + ArithPair.new(2, 20) * ArithPair.new(3, 30);
[00000000] (7, 610)


20.

Для того чтобы вставить в объект функцию нужно использовать метод setSlot:

var o = Object.clone | {};
// Here we can use f as any regular value
o.setSlot("m1", function () { echo("Hello") }) | {};
// This is strictly equivalent
var o.m2 = function () { echo("Hello") } | {};
o.m1;
[00000000] *** Hello
o.m2;
[00000000] *** Hello


Это позволяет писать очень интересный код, например функцию, которая в качестве аргумента принимает другую функцию.
Пример — функция all(), которая принимает в качестве параметров список и функцию и для каждого элемента списка вызывает данную функцию

function all(list, predicate)
{
	for (var elt : list)
		if (!predicate(elt))
			return false;
	return true;
} | {};
// проверим являются ли все элементы списка положительными
function positive(x) { x >= 0 } | {};
all([1, 2, 3], getSlot("positive"));
[00000000] true
all([1, 2, -3], getSlot("positive"));
[00000000] false


Метод all уже существует. Его можно вызвать
list.all(predicate)


21. Лямбда-функции
Лямбда-функция — это функция не привязанная к конкретному имени (их удобно использовать в функциях в качестве callback-параметра ).

Пример создания такой анонимной функции в urbiScript:

// создание анонимной функции
function (x) {x + 1} | {};
// создание такой функции позволяет на лету
// передать её в качестве параметра метода "all":
[1, 2, 3].all(function (x) { x > 0});
[00000000] true


22. Ленивые аргументы (Lazy arguments)

в urbiScript по-умолчанию аргументы функции задаются точно, но с помощью объекта call можно вручную получить доступ к переданным аргументам функции.

// аргументы функции не указываются
function first
{
	// вызываем первый аргумент
	call.evalArgAt(0);
} | {};
first(echo("first"), echo("second"));
[00000000] *** first
function reverse
{
	call.evalArgAt(1);
	call.evalArgAt(0);
} | {};
reverse(echo("first"), echo("second"));
[00000000] *** second
[00000000] *** first


Отличный пример — логический оператор:

function myAnd
{
	if (call.evalArgAt(0))
		call.evalArgAt(1)
	else
		false;
}|;
function f()
{
	echo("f executed");
	return true;
}|;
myAnd(false, f());
[00000000] false
myAnd(true, f());
[00000000] *** f executed
[00000000] true


Читать далее: введение в urbiScript — часть 4
  • 0
  • 17 сентября 2010, 10:19
  • noonv

Комментарии (0)

RSS свернуть / развернуть

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.