При определении пользовательского оператора от ограниченного набора односимвольных операторов, которые могут быть и инфиксными и префиксными операторами (+ - % &
) Я решил использовать амперсанд, так как это - единственный из тех операторов, которые у меня до сих пор не было случая для использования в моем коде F#. Я обосновал, что с тех пор и, кажется, справедливо ограничил использование в F#, переопределение его наименее сбивало бы с толку людей, пользующихся моей библиотекой.
Однако, когда я делаю так, я получаю предупреждение компилятора:
'&' оператор не должен обычно переопределяться. Рассмотрите использование другого имени оператора.
Мой вопрос, почему этот по-видимому редкий оператор генерирует это предупреждающее сообщение, в то время как наиболее часто используемые операторы как плюс и минус не делают? Кроме того, как серьезно я должен взять это предупреждение?
Невозможно вызвать методы, использующие параметры byref. Это может быть или не быть большой проблемой для вас.
Что касается вашего вопроса о «шаблонах И», вот краткий пример. Однако следует отметить, что определение собственного унарного оператора и
не повлияет на это поведение одного пути или другой.
let (|Contains|_|) (s:string) (x:string) =
if (x.Contains(s)) then Some() else None
match "test" with
| Contains "e" & Contains "s" -> printfn "Success!"
| _ -> ()
Как ни странно, я вижу только предупреждение, которое вы упоминаете при определении бинарного оператора (&)
, а не унарного оператора (~ &)
.
EDIT
Хотя я не вижу, что он явно вызван в спецификации, похоже, что двоичный оператор &
используется в качестве синонима двоичного оператора & &
. Я бы предположил, что предложение не переопределять этот оператор существует, потому что это оператор короткого замыкания, но ваша перегрузка не может быть.
Среда выполнения Perl regex работает гораздо быстрее при работе с «фиксированными» или «привязанными» подстроками, а не с «плавающими» подстроками. Подстрока фиксируется, когда ее можно заблокировать в определенном месте исходной последовательности. И '^', и '$' обеспечивают эту привязку. Однако при использовании чередования «|» компилятор не распознает варианты как фиксированные, поэтому использует менее оптимизированный код для сканирования всей последовательности. И в конце процесса поиск фиксированных последовательностей дважды намного быстрее, чем поиск плавающей последовательности один раз. В связи с этим, чтение perl's regcomp.c заставит вас ослепнуть.
Обновить : Вот некоторые дополнительные детали. Вы можете запустить perl с флагом '-Dr', если вы скомпилировали его с поддержкой отладки и он будет выгружать данные компиляции regex. Вот что вы получаете:
~# debugperl -Dr -e 's/^\s+//g'
Compiling REx `^\s+'
size 4 Got 36 bytes for offset annotations.
first at 2
synthetic stclass "ANYOF[\11\12\14\15 {unicode_all}]".
1: BOL(2)
2: PLUS(4)
3: SPACE(0)
4: END(0)
stclass "ANYOF[\11\12\14\15 {unicode_all}]" anchored(BOL) minlen 1
# debugperl -Dr -e 's/^\s+|\s+$//g'
Compiling REx `^\s+|\s+$'
size 9 Got 76 bytes for offset annotations.
1: BRANCH(5)
2: BOL(3)
3: PLUS(9)
4: SPACE(0)
5: BRANCH(9)
6: PLUS(8)
7: SPACE(0)
8: EOL(9)
9: END(0)
minlen 1
Обратите внимание на слово «заякоренный» в первой свалке.
-121--2678279- При создании пользовательского оператора я, как правило, предпочитаю находить простую комбинацию символов, которая не конфликтует ни с одним существующим оператором F #. Верно то, что набор символов очень ограничен, поэтому это не всегда возможно. Однако можно, например, определить что-то вроде - & -
, и часто можно выбрать какую-либо комбинацию, которая отражает значение оператора. Из любопытства, каким будет смысл вашего оператора?
В любом случае, когда я не могу найти хорошее имя оператора, то я считаю это признаком того, что, может быть, я не должен использовать пользовательский оператор (в конце концов, многие языки живут без них довольно легко). Я думаю, что основное использование пользовательских операторов, вероятно, некоторые специализированные математические вещи. Оператор (например, a - & - b
) часто можно заменить функцией, используемой при конвейерной обработке (например, a | > (В)
). Существует также аккуратный трюк , позволяющий использовать функции в качестве операторов инфикса.
В случае &
, я думаю, что это вполне разумный вариант игнорировать предупреждение, если вы хорошо используете для оператора и поведение оператора, которого вы хотите определить, каким-то образом соответствует интуиции о символе &
.
EDIT Определение собственного оператора и
не приведет к прерыванию другого использования символа и
(при согласовании шаблонов). Вот пример и образец :
// define custom & operator
let (&) a b = a + b
match 2 with
| num1 & num2 -> num1 + num2 // Still works fine
и образцы позволяют сопоставить одно значение с несколькими узоров в одном образце (в примере выше мы просто связываем его с двумя различными значениями)
Вы не сможете вызывать методы, которые принимают параметры byref. Это может быть, а может и не иметь для вас большого значения.
Что касается вашего вопроса о «шаблонах И», вот небольшой пример. Однако обратите внимание, что определение собственного унарного оператора и
не повлияет на это поведение тем или иным образом.
let (|Contains|_|) (s:string) (x:string) =
if (x.Contains(s)) then Some() else None
match "test" with
| Contains "e" & Contains "s" -> printfn "Success!"
| _ -> ()
Как ни странно, я вижу только предупреждение, которое вы упоминаете при определении бинарного оператора (&)
, а не унарного оператора (~ &)
.
РЕДАКТИРОВАТЬ
Хотя я не вижу, чтобы он явно вызывался в спецификации, похоже, что двоичный оператор &
используется как синоним двоичного оператора &&
. Я предполагаю, что предложение не переопределять этот оператор существует, потому что это оператор короткого замыкания, но ваша перегрузка не может быть.